Browse Source

Implement image and memory buffers

Implementation of image.h and image.c; AC strategy implementation was slightly adjusted to reduce errors.
pull/3153/head
winscripter 2 weeks ago
parent
commit
21ff33f23c
  1. 38
      src/ImageSharp/Formats/Jxl/Ac/JxlAcStrategyImage.cs
  2. 12
      src/ImageSharp/Formats/Jxl/Memory/IJxlMemoryManager.cs
  3. 14
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3B.cs
  4. 14
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3F.cs
  5. 14
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3I.cs
  6. 14
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3S.cs
  7. 14
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3U.cs
  8. 34
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageB.cs
  9. 23
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageF.cs
  10. 23
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageI.cs
  11. 23
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageS.cs
  12. 23
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageSB.cs
  13. 23
      src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageU.cs
  14. 85
      src/ImageSharp/Formats/Jxl/Memory/JxlImage3{T}.cs
  15. 18
      src/ImageSharp/Formats/Jxl/Memory/JxlMemoryManager.cs
  16. 115
      src/ImageSharp/Formats/Jxl/Memory/JxlPlaneBase.cs
  17. 36
      src/ImageSharp/Formats/Jxl/Memory/JxlPlane{T}.cs

38
src/ImageSharp/Formats/Jxl/Ac/JxlAcStrategyImage.cs

@ -2,42 +2,40 @@
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using SixLabors.ImageSharp.Formats.Jxl.Memory;
using SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
namespace SixLabors.ImageSharp.Formats.Jxl.Ac;
internal sealed class JxlAcStrategyImage
internal sealed class JxlAcStrategyImage : IDisposable
{
private const byte Invalid = byte.MaxValue; // 255
private JxlImageB? layers;
private readonly Memory<byte> row;
private readonly int stride;
private Memory<byte> row;
private int stride;
public JxlMemoryManager MemoryManager => this.layers.MemoryManager;
public int XSize => this.layers!.XSize;
public int XSize => this.layers.XSize;
public int YSize => this.layers!.YSize;
public int YSize => this.layers.YSize;
public int PixelsPerRow => this.layers.PixelsPerRow;
public int PixelsPerRow => this.layers!.PixelsPerRow;
public JxlAcStrategyRow GetRow(int y, int xPrefix = 0)
{
ReadOnlyMemory<byte> layerRow = this.layers.GetRow(y);
ReadOnlyMemory<byte> layerRow = this.layers!.GetRowBytesMemory(y);
ReadOnlyMemory<byte> row = layerRow[xPrefix..];
return new JxlAcStrategyRow(row);
}
public static JxlAcStrategyImage Create(JxlMemoryManager memoryManager, int xSize, int ySize)
public static JxlAcStrategyImage Create(Configuration memoryManager, int xSize, int ySize)
{
JxlAcStrategyImage image = new()
{
layers = JxlImageB.Create(memoryManager, xSize, ySize)
layers = new JxlImageB(memoryManager, xSize, ySize)
};
image.row = image.layers.GetRow(0);
image.row = image.layers.GetRowBytesMemory(0);
image.stride = image.layers.PixelsPerRow;
return image;
@ -48,11 +46,11 @@ internal sealed class JxlAcStrategyImage
int value = 0;
int compare = ((int)type << 1) | 1;
for (int y = 0; y < this.layers.YSize; y++)
for (int y = 0; y < this.layers!.YSize; y++)
{
ReadOnlySpan<byte> row = this.layers.GetRowSpan(y);
ReadOnlySpan<byte> row = this.layers!.GetRow(y);
for (int x = 0; x < this.layers.XSize; x++)
for (int x = 0; x < this.layers!.XSize; x++)
{
if (row[x] == compare)
{
@ -100,7 +98,7 @@ internal sealed class JxlAcStrategyImage
#if DEBUG
JxlAcStrategy strategy = new(type);
Debug.Assert(y + strategy.CoveredBlocksY <= this.layers.YSize, "Invalid range");
Debug.Assert(y + strategy.CoveredBlocksY <= this.layers!.YSize, "Invalid range");
Debug.Assert(x + strategy.CoveredBlocksX <= this.layers.XSize, "Invalid range");
#endif
@ -112,4 +110,10 @@ internal sealed class JxlAcStrategyImage
public void FillDct8() => this.FillDct8(in this.layers.GetRectangle());
public void FillInvalid() => this.FillImage(Invalid, this.layers);
public void Dispose()
{
this.layers?.Dispose();
GC.SuppressFinalize(this);
}
}

12
src/ImageSharp/Formats/Jxl/Memory/IJxlMemoryManager.cs

@ -1,12 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
namespace SixLabors.ImageSharp.Formats.Jxl.Memory;
internal interface IJxlMemoryManager
{
IMemoryOwner<T> Allocate<T>(int size);
IMemoryOwner<byte> Allocate(int size);
}

14
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3B.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a three-plane, 2D raster image of type <see cref="byte"/>.
/// </summary>
internal sealed class JxlImage3B : JxlImage3<byte>
{
public JxlImage3B()
{
}
}

14
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3F.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a three-plane, 2D raster image of type <see cref="float"/>.
/// </summary>
internal sealed class JxlImage3F : JxlImage3<float>
{
public JxlImage3F()
{
}
}

14
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3I.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a three-plane, 2D raster image of type <see cref="int"/>.
/// </summary>
internal sealed class JxlImage3I : JxlImage3<int>
{
public JxlImage3I()
{
}
}

14
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3S.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a three-plane, 2D raster image of type <see cref="short"/>.
/// </summary>
internal sealed class JxlImage3S : JxlImage3<short>
{
public JxlImage3S()
{
}
}

14
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImage3U.cs

@ -0,0 +1,14 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a three-plane, 2D raster image of type <see cref="ushort"/>.
/// </summary>
internal sealed class JxlImage3U : JxlImage3<ushort>
{
public JxlImage3U()
{
}
}

34
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageB.cs

@ -0,0 +1,34 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="byte"/>.
/// </summary>
internal sealed class JxlImageB : JxlPlane<byte>
{
public JxlImageB()
{
}
public JxlImageB(int width, int height)
: base(width, height)
{
}
public JxlImageB(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
public Memory<byte> GetRowBytesMemory(int y)
{
Debug.Assert(y < this.YSize, "Attempted to access out-of-bounds Y coordinate");
Memory<byte> row = this.Bytes[(y * this.BytesPerRow)..];
return row;
}
}

23
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageF.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="float"/>.
/// </summary>
internal sealed class JxlImageF : JxlPlane<float>
{
public JxlImageF()
{
}
public JxlImageF(int width, int height)
: base(width, height)
{
}
public JxlImageF(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
}

23
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageI.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="int"/>.
/// </summary>
internal sealed class JxlImageI : JxlPlane<int>
{
public JxlImageI()
{
}
public JxlImageI(int width, int height)
: base(width, height)
{
}
public JxlImageI(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
}

23
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageS.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="short"/>.
/// </summary>
internal sealed class JxlImageS : JxlPlane<short>
{
public JxlImageS()
{
}
public JxlImageS(int width, int height)
: base(width, height)
{
}
public JxlImageS(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
}

23
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageSB.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="sbyte"/>.
/// </summary>
internal sealed class JxlImageSB : JxlPlane<sbyte>
{
public JxlImageSB()
{
}
public JxlImageSB(int width, int height)
: base(width, height)
{
}
public JxlImageSB(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
}

23
src/ImageSharp/Formats/Jxl/Memory/ImageTypes/JxlImageU.cs

@ -0,0 +1,23 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes;
/// <summary>
/// Represents a single-plane, 2D raster image of type <see cref="ushort"/>.
/// </summary>
internal sealed class JxlImageU : JxlPlane<ushort>
{
public JxlImageU()
{
}
public JxlImageU(int width, int height)
: base(width, height)
{
}
public JxlImageU(Configuration configuration, int xSize, int ySize, int prePadding = 0)
: base(xSize, ySize)
=> this.Allocate(configuration, prePadding);
}

85
src/ImageSharp/Formats/Jxl/Memory/JxlImage3{T}.cs

@ -0,0 +1,85 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jxl.Memory;
// NOTE: Do not seal this class.
internal class JxlImage3<T>
where T : unmanaged
{
private const int PlaneCount = 3;
private JxlPlane<T>[] planes = new JxlPlane<T>[3];
public JxlImage3()
{
}
public JxlImage3(JxlImage3<T> other)
{
for (int i = 0; i < PlaneCount; i++)
{
this.planes[i] = other.planes[i];
}
}
public int XSize => this.planes[0].XSize;
public int YSize => this.planes[0].YSize;
public int BytesPerRow => this.planes[0].BytesPerRow;
public int PixelsPerRow => this.planes[0].PixelsPerRow;
public Span<T> PlaneRow(int plane, int row)
{
this.PlaneRowBoundsCheck(plane, row);
int rowOffset = row * this.planes[0].BytesPerRow;
Span<T> rowSpan = MemoryMarshal.Cast<byte, T>(this.planes[plane].BytesSpan[rowOffset..]);
return rowSpan;
}
public JxlPlane<T> Plane(int index) => this.planes[index];
public void Swap(JxlImage3<T> other)
{
for (int i = 0; i < PlaneCount; i++)
{
other.planes[i].Swap(this.planes[i]);
}
}
public static JxlImage3<T> Create(Configuration configuration, int xSize, int ySize)
{
JxlPlane<T> plane0 = JxlPlane<T>.Create(configuration, xSize, ySize);
JxlPlane<T> plane1 = JxlPlane<T>.Create(configuration, xSize, ySize);
JxlPlane<T> plane2 = JxlPlane<T>.Create(configuration, xSize, ySize);
return new JxlImage3<T>()
{
planes = [plane0, plane1, plane2]
};
}
public bool ShrinkTo(int x, int y)
{
for (int i = 0; i < PlaneCount; i++)
{
if (!this.planes[i].ShrinkTo(x, y))
{
return false;
}
}
return true;
}
[Conditional("DEBUG")]
private void PlaneRowBoundsCheck(int c, int y) =>
Debug.Assert(c < PlaneCount && y < this.YSize, "The bounds check has failed");
}

18
src/ImageSharp/Formats/Jxl/Memory/JxlMemoryManager.cs

@ -1,18 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
namespace SixLabors.ImageSharp.Formats.Jxl.Memory;
/// <summary>
/// Allows allocation and deallocation of managed memory.
/// </summary>
internal sealed class JxlMemoryManager : IJxlMemoryManager
{
public static readonly JxlMemoryManager Instance = new();
public IMemoryOwner<T> Allocate<T>(int size) => MemoryPool<T>.Shared.Rent(size);
public IMemoryOwner<byte> Allocate(int size) => this.Allocate<byte>(size);
}

115
src/ImageSharp/Formats/Jxl/Memory/JxlPlaneBase.cs

@ -0,0 +1,115 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jxl.Memory;
// NOTE: Do not seal this type.
internal class JxlPlaneBase : IDisposable
{
private IMemoryOwner<byte>? bytes;
public JxlPlaneBase(int xSize, int ySize, int sizeOfT)
{
this.XSize = xSize;
this.YSize = ySize;
this.OriginalXSize = xSize;
this.OriginalYSize = ySize;
this.BytesPerRow = 0;
this.Size = sizeOfT;
}
public JxlPlaneBase()
: this(0, 0, 0)
{
}
public int BytesPerRow { get; private set; }
public int XSize { get; private set; }
public int YSize { get; private set; }
public Memory<byte> Bytes =>
#if DEBUG
this.bytes?.Memory ?? throw new InvalidOperationException("Bytes are missing");
#else
return this.bytes!.Memory;
#endif
public Span<byte> BytesSpan => this.Bytes.Span;
protected int Size { get; set; }
protected int OriginalXSize { get; set; }
protected int OriginalYSize { get; set; }
public bool Allocate(Configuration configuration, int prePadding)
{
if (this.bytes != null || this.BytesPerRow != 0)
{
return false;
}
if (this.XSize == 0 || this.YSize == 0)
{
return true;
}
int totalBytes = unchecked(this.YSize * this.BytesPerRow);
this.bytes = configuration.MemoryAllocator.Allocate<byte>(totalBytes + (prePadding * this.Size));
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ShrinkTo(int x, int y)
{
if (x <= this.OriginalXSize || y <= this.OriginalYSize)
{
return false;
}
Debug.Assert(x <= this.OriginalXSize, "ShrinkTo cannot expand memory");
Debug.Assert(y <= this.OriginalYSize, "ShrinkTo cannot expand memory");
this.XSize = x;
this.YSize = y;
return true;
}
protected Span<T> GetRowBase<T>(int y)
where T : unmanaged
{
Debug.Assert(y < this.YSize, "Attempted to access out-of-bounds Y coordinate");
Span<byte> row = this.Bytes.Span[(y * this.BytesPerRow)..];
return MemoryMarshal.Cast<byte, T>(row);
}
protected void SetBytes(IMemoryOwner<byte> bytes) => this.bytes = bytes;
public void Swap(JxlPlaneBase other)
{
(this.XSize, other.XSize) = (other.XSize, this.XSize);
(this.YSize, other.YSize) = (other.YSize, this.YSize);
(this.OriginalXSize, other.OriginalXSize) = (other.OriginalXSize, this.OriginalXSize);
(this.OriginalYSize, other.OriginalYSize) = (other.OriginalYSize, this.OriginalYSize);
(this.BytesPerRow, other.BytesPerRow) = (other.BytesPerRow, this.BytesPerRow);
(this.bytes, other.bytes) = (other.bytes, this.bytes);
}
public void Dispose()
{
this.bytes?.Dispose();
GC.SuppressFinalize(this);
}
}

36
src/ImageSharp/Formats/Jxl/Memory/JxlPlane{T}.cs

@ -0,0 +1,36 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Jxl.Memory;
// NOTE: Do not seal this class.
internal class JxlPlane<T> : JxlPlaneBase
where T : unmanaged
{
public JxlPlane()
{
}
public unsafe JxlPlane(int width, int height)
: base(width, height, sizeof(T))
{
}
public unsafe int PixelsPerRow => this.BytesPerRow / sizeof(T);
public static JxlPlane<T> Create(Configuration configuration, int xSize, int ySize, int prePadding = 0)
{
JxlPlane<T> plane = new(xSize, ySize);
bool allocated = plane.Allocate(configuration, prePadding);
if (!allocated)
{
throw new InvalidOperationException("Failed to allocate a JPEG XL plane");
}
return plane;
}
public Span<T> GetRow(int y) => this.GetRowBase<T>(y);
}
Loading…
Cancel
Save