Browse Source

Changed PixelRow into a PixelArea.

af/merge-core
Dirk Lemstra 9 years ago
parent
commit
e23d8dfe2c
  1. 6
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  2. 4
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  3. 4
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  4. 2
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  5. 243
      src/ImageSharp/Image/PixelAccessor.cs
  6. 89
      src/ImageSharp/Image/PixelArea.cs
  7. 122
      src/ImageSharp/PixelAccessor.cs
  8. 8
      tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

6
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -281,7 +281,7 @@ namespace ImageSharp.Formats
const int ComponentCount = 2;
TColor color = default(TColor);
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.XYZ))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(width, ComponentOrder.XYZ))
{
for (int y = 0; y < height; y++)
{
@ -320,7 +320,7 @@ namespace ImageSharp.Formats
where TPacked : struct
{
int padding = CalculatePadding(width, 3);
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.ZYX, padding))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(width, ComponentOrder.ZYX, padding))
{
for (int y = 0; y < height; y++)
{
@ -346,7 +346,7 @@ namespace ImageSharp.Formats
where TPacked : struct
{
int padding = CalculatePadding(width, 4);
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(width, ComponentOrder.ZYXW, padding))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(width, ComponentOrder.ZYXW, padding))
{
for (int y = 0; y < height; y++)
{

4
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -155,7 +155,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
{
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(pixels.Width, ComponentOrder.ZYXW, this.padding))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(pixels.Width, ComponentOrder.ZYXW, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)
{
@ -176,7 +176,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
{
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(pixels.Width, ComponentOrder.ZYX, this.padding))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(pixels.Width, ComponentOrder.ZYX, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)
{

4
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -339,7 +339,7 @@ namespace ImageSharp.Formats
using (PixelAccessor<TColor, TPacked> pixelAccessor = image.Lock())
{
using (PixelRow<TColor, TPacked> pixelRow = new PixelRow<TColor, TPacked>(imageWidth, ComponentOrder.XYZW))
using (PixelArea<TColor, TPacked> pixelRow = new PixelArea<TColor, TPacked>(imageWidth, ComponentOrder.XYZW))
{
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
{
@ -445,7 +445,7 @@ namespace ImageSharp.Formats
}
else
{
using (PixelRow<TColor, TPacked> emptyRow = new PixelRow<TColor, TPacked>(this.restoreArea.Value.Width, ComponentOrder.XYZW))
using (PixelArea<TColor, TPacked> emptyRow = new PixelArea<TColor, TPacked>(this.restoreArea.Value.Width, ComponentOrder.XYZW))
{
using (PixelAccessor<TColor, TPacked> pixelAccessor = frame.Lock())
{

2
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -322,7 +322,7 @@ namespace ImageSharp.Formats
where TPacked : struct
{
// We can use the optimized PixelAccessor here and copy the bytes in unmanaged memory.
using (PixelRow<TColor, TPacked> pixelRow = new PixelRow<TColor, TPacked>(this.width, rawScanline, this.bytesPerPixel == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ))
using (PixelArea<TColor, TPacked> pixelRow = new PixelArea<TColor, TPacked>(this.width, rawScanline, this.bytesPerPixel == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ))
{
pixels.CopyTo(pixelRow, row);
}

243
src/ImageSharp/Image/PixelAccessor.cs

@ -177,27 +177,32 @@ namespace ImageSharp
/// <summary>
/// Copied a row of pixels from the image.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param>
/// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed.
/// </exception>
public void CopyFrom(PixelRow<TColor, TPacked> row, int targetY, int targetX = 0)
public void CopyFrom(PixelArea<TColor, TPacked> area, int targetY, int targetX = 0)
{
switch (row.ComponentOrder)
int width = Math.Min(area.Width, this.Width - targetX);
int height = Math.Min(area.Height, this.Height - targetY);
CheckDimensions(width, height);
switch (area.ComponentOrder)
{
case ComponentOrder.ZYX:
this.CopyFromZYX(row, targetY, targetX, Math.Min(row.Width, this.Width));
this.CopyFromZYX(area, targetY, targetX, width, height);
break;
case ComponentOrder.ZYXW:
this.CopyFromZYXW(row, targetY, targetX, Math.Min(row.Width, this.Width));
this.CopyFromZYXW(area, targetY, targetX, width, height);
break;
case ComponentOrder.XYZ:
this.CopyFromXYZ(row, targetY, targetX, Math.Min(row.Width, this.Width));
this.CopyFromXYZ(area, targetY, targetX, width, height);
break;
case ComponentOrder.XYZW:
this.CopyFromXYZW(row, targetY, targetX, Math.Min(row.Width, this.Width));
this.CopyFromXYZW(area, targetY, targetX, width, height);
break;
default:
throw new NotSupportedException();
@ -205,28 +210,34 @@ namespace ImageSharp
}
/// <summary>
/// Copied a row of pixels to the image.
/// Copied an area of pixels to the image.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param>
/// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed.
/// </exception>
public void CopyTo(PixelRow<TColor, TPacked> row, int sourceY)
public void CopyTo(PixelArea<TColor, TPacked> area, int sourceY, int sourceX = 0)
{
switch (row.ComponentOrder)
int width = Math.Min(area.Width, this.Width - sourceX);
int height = Math.Min(area.Height, this.Height - sourceY);
CheckDimensions(width, height);
switch (area.ComponentOrder)
{
case ComponentOrder.ZYX:
this.CopyToZYX(row, sourceY, Math.Min(row.Width, this.Width));
this.CopyToZYX(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.ZYXW:
this.CopyToZYXW(row, sourceY, Math.Min(row.Width, this.Width));
this.CopyToZYXW(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.XYZ:
this.CopyToXYZ(row, sourceY, Math.Min(row.Width, this.Width));
this.CopyToXYZ(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.XYZW:
this.CopyToXYZW(row, sourceY, Math.Min(row.Width, this.Width));
this.CopyToXYZW(area, sourceY, sourceX, width, height);
break;
default:
throw new NotSupportedException();
@ -271,166 +282,202 @@ namespace ImageSharp
}
/// <summary>
/// Copies from a row in <see cref="ComponentOrder.ZYX"/> format.
/// Copies from an area in <see cref="ComponentOrder.ZYX"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyFromZYX(PixelRow<TColor, TPacked> row, int targetY, int targetX, int width)
/// <param name="height">The height.</param>
protected virtual void CopyFromZYX(PixelArea<TColor, TPacked> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, 255);
Unsafe.Write(destination, packed);
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, 255);
Unsafe.Write(destination, packed);
source += 3;
destination += size;
source += 3;
destination += size;
}
}
}
/// <summary>
/// Copies from a row in <see cref="ComponentOrder.ZYXW"/> format.
/// Copies from an area in <see cref="ComponentOrder.ZYXW"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyFromZYXW(PixelRow<TColor, TPacked> row, int targetY, int targetX, int width)
/// <param name="height">The height.</param>
protected virtual void CopyFromZYXW(PixelArea<TColor, TPacked> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, *(source + 3));
Unsafe.Write(destination, packed);
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
source += 4;
destination += size;
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*(source + 2), *(source + 1), *source, *(source + 3));
Unsafe.Write(destination, packed);
source += 4;
destination += size;
}
}
}
/// <summary>
/// Copies from a row in <see cref="ComponentOrder.XYZ"/> format.
/// Copies from an area in <see cref="ComponentOrder.XYZ"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyFromXYZ(PixelRow<TColor, TPacked> row, int targetY, int targetX, int width)
/// <param name="height">The height.</param>
protected virtual void CopyFromXYZ(PixelArea<TColor, TPacked> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), 255);
Unsafe.Write(destination, packed);
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), 255);
Unsafe.Write(destination, packed);
source += 3;
destination += size;
source += 3;
destination += size;
}
}
}
/// <summary>
/// Copies from a row in <see cref="ComponentOrder.XYZW"/> format.
/// Copies from an area in <see cref="ComponentOrder.XYZW"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyFromXYZW(PixelRow<TColor, TPacked> row, int targetY, int targetX, int width)
/// <param name="height">The height.</param>
protected virtual void CopyFromXYZW(PixelArea<TColor, TPacked> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>();
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), *(source + 3));
Unsafe.Write(destination, packed);
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
for (int x = 0; x < width; x++)
{
packed.PackFromBytes(*source, *(source + 1), *(source + 2), *(source + 3));
Unsafe.Write(destination, packed);
source += 4;
destination += size;
source += 4;
destination += size;
}
}
}
/// <summary>
/// Copies to a row in <see cref="ComponentOrder.ZYX"/> format.
/// Copies to an area in <see cref="ComponentOrder.ZYX"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="sourceY">The target row index.</param>
/// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyToZYX(PixelRow<TColor, TPacked> row, int sourceY, int width)
/// <param name="height">The height.</param>
protected virtual void CopyToZYX(PixelArea<TColor, TPacked> area, int sourceY, int sourceX, int width, int height)
{
int offset = 0;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.ZYX);
offset += 3;
int offset = y * area.RowByteCount;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.ZYX);
offset += 3;
}
}
}
/// <summary>
/// Copies to a row in <see cref="ComponentOrder.ZYXW"/> format.
/// Copies to an area in <see cref="ComponentOrder.ZYXW"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="sourceY">The target row index.</param>
/// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyToZYXW(PixelRow<TColor, TPacked> row, int sourceY, int width)
/// <param name="height">The height.</param>
protected virtual void CopyToZYXW(PixelArea<TColor, TPacked> area, int sourceY, int sourceX, int width, int height)
{
int offset = 0;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.ZYXW);
offset += 4;
int offset = y * area.RowByteCount;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.ZYXW);
offset += 4;
}
}
}
/// <summary>
/// Copies to a row in <see cref="ComponentOrder.XYZ"/> format.
/// Copies to an area in <see cref="ComponentOrder.XYZ"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="sourceY">The target row index.</param>
/// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyToXYZ(PixelRow<TColor, TPacked> row, int sourceY, int width)
/// <param name="height">The height.</param>
protected virtual void CopyToXYZ(PixelArea<TColor, TPacked> area, int sourceY, int sourceX, int width, int height)
{
int offset = 0;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.XYZ);
offset += 3;
int offset = y * area.RowByteCount;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.XYZ);
offset += 3;
}
}
}
/// <summary>
/// Copies to a row in <see cref="ComponentOrder.XYZW"/> format.
/// Copies to an area in <see cref="ComponentOrder.XYZW"/> format.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="sourceY">The target row index.</param>
/// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param>
/// <param name="width">The width.</param>
protected virtual void CopyToXYZW(PixelRow<TColor, TPacked> row, int sourceY, int width)
/// <param name="height">The height.</param>
protected virtual void CopyToXYZW(PixelArea<TColor, TPacked> area, int sourceY, int sourceX, int width, int height)
{
int offset = 0;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.XYZW);
offset += 4;
int offset = y * area.RowByteCount;
for (int x = 0; x < width; x++)
{
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.XYZW);
offset += 4;
}
}
}
@ -446,6 +493,20 @@ namespace ImageSharp
return this.pixelsBase + ((targetY * this.Width) * Unsafe.SizeOf<TColor>());
}
[Conditional("DEBUG")]
private void CheckDimensions(int width, int height)
{
if (width < 1)
{
throw new ArgumentOutOfRangeException(nameof(width), width, $"Invalid area size specified.");
}
if (height < 1)
{
throw new ArgumentOutOfRangeException(nameof(height), height, $"Invalid area size specified.");
}
}
/// <summary>
/// Checks the coordinates to ensure they are within bounds.
/// </summary>

89
src/ImageSharp/Image/PixelRow.cs → src/ImageSharp/Image/PixelArea.cs

@ -1,4 +1,4 @@
// <copyright file="PixelRow.cs" company="James Jackson-South">
// <copyright file="PixelArea.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -6,16 +6,17 @@
namespace ImageSharp
{
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Represents a row of generic <see cref="Image{TColor,TPacked}"/> pixels.
/// Represents an area of generic <see cref="Image{TColor,TPacked}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
public sealed unsafe class PixelRow<TColor, TPacked> : IDisposable
public sealed unsafe class PixelArea<TColor, TPacked> : IDisposable
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
{
@ -41,7 +42,7 @@ namespace ImageSharp
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// Initializes a new instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="bytes">The bytes.</param>
@ -49,15 +50,29 @@ namespace ImageSharp
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if <paramref name="bytes"></paramref> is the incorrect length.
/// </exception>
public PixelRow(int width, byte[] bytes, ComponentOrder componentOrder)
public PixelArea(int width, byte[] bytes, ComponentOrder componentOrder)
: this(width, 1, bytes, componentOrder)
{
if (bytes.Length != width * GetComponentCount(componentOrder))
{
throw new ArgumentOutOfRangeException($"Invalid byte array length. Length {bytes.Length}; Should be {width * GetComponentCount(componentOrder)}.");
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="bytes">The bytes.</param>
/// <param name="componentOrder">The component order.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if <paramref name="bytes"></paramref> is the incorrect length.
/// </exception>
public PixelArea(int width, int height, byte[] bytes, ComponentOrder componentOrder)
{
this.CheckBytesLength(width, height, bytes, componentOrder);
this.Width = width;
this.Height = height;
this.ComponentOrder = componentOrder;
this.RowByteCount = width * GetComponentCount(componentOrder);
this.Bytes = bytes;
this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
@ -67,26 +82,40 @@ namespace ImageSharp
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// Initializes a new instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width. </param>
/// <param name="width">The width.</param>
/// <param name="componentOrder">The component order.</param>
public PixelRow(int width, ComponentOrder componentOrder)
: this(width, componentOrder, 0)
public PixelArea(int width, ComponentOrder componentOrder)
: this(width, 1, componentOrder, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// Initializes a new instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width. </param>
/// <param name="componentOrder">The component order.</param>
/// <param name="padding">The number of bytes to pad each row.</param>
public PixelRow(int width, ComponentOrder componentOrder, int padding)
public PixelArea(int width, ComponentOrder componentOrder, int padding)
: this(width, 1, componentOrder, padding)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="componentOrder">The component order.</param>
/// <param name="padding">The number of bytes to pad each row.</param>
public PixelArea(int width, int height, ComponentOrder componentOrder, int padding)
{
this.Width = width;
this.Height = height;
this.ComponentOrder = componentOrder;
this.Bytes = new byte[(width * GetComponentCount(componentOrder)) + padding];
this.RowByteCount = (width * GetComponentCount(componentOrder)) + padding;
this.Bytes = new byte[this.RowByteCount * height];
this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
// TODO: Why is Resharper warning us about an impure method call?
@ -95,9 +124,9 @@ namespace ImageSharp
}
/// <summary>
/// Finalizes an instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// Finalizes an instance of the <see cref="PixelArea{TColor,TPacked}"/> class.
/// </summary>
~PixelRow()
~PixelArea()
{
this.Dispose();
}
@ -128,7 +157,17 @@ namespace ImageSharp
public int Width { get; }
/// <summary>
/// Reads the stream to the row.
/// Gets the height.
/// </summary>
public int Height { get; }
/// <summary>
/// Gets number of bytes in a row.
/// </summary>
public int RowByteCount { get; }
/// <summary>
/// Reads the stream to the area.
/// </summary>
/// <param name="stream">The stream.</param>
public void Read(Stream stream)
@ -137,7 +176,7 @@ namespace ImageSharp
}
/// <summary>
/// Writes the row to the stream.
/// Writes the area to the stream.
/// </summary>
/// <param name="stream">The stream.</param>
public void Write(Stream stream)
@ -210,5 +249,15 @@ namespace ImageSharp
throw new NotSupportedException();
}
[Conditional("DEBUG")]
private void CheckBytesLength(int width, int height, byte[] bytes, ComponentOrder componentOrder)
{
int requiredLength = (width * GetComponentCount(componentOrder)) * height;
if (bytes.Length != requiredLength)
{
throw new ArgumentOutOfRangeException(nameof(bytes), $"Invalid byte array length. Length {bytes.Length}; Should be {requiredLength}.");
}
}
}
}

122
src/ImageSharp/PixelAccessor.cs

@ -22,91 +22,111 @@ namespace ImageSharp
}
/// <inheritdoc />
protected override void CopyFromXYZW(PixelRow<Color, uint> row, int targetY, int targetX, int width)
protected override void CopyFromXYZW(PixelArea<Color, uint> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
uint byteCount = (uint)width * 4;
Unsafe.CopyBlock(destination, source, (uint)width * 4);
for (int y = 0; y < height; y++)
{
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
Unsafe.CopyBlock(destination, source, byteCount);
}
}
/// <inheritdoc />
protected override void CopyFromXYZ(PixelRow<Color, uint> row, int targetY, int targetX, int width)
protected override void CopyFromXYZ(PixelArea<Color, uint> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24));
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
source += 3;
destination += 4;
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24));
source += 3;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyFromZYX(PixelRow<Color, uint> row, int targetY, int targetX, int width)
protected override void CopyFromZYX(PixelArea<Color, uint> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24));
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24));
source += 3;
destination += 4;
source += 3;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyFromZYXW(PixelRow<Color, uint> row, int targetY, int targetX, int width)
protected override void CopyFromZYXW(PixelArea<Color, uint> area, int targetY, int targetX, int width, int height)
{
byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY) + targetX;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24));
byte* source = area.PixelBase + (y * area.RowByteCount);
byte* destination = this.GetRowPointer(targetY + y) + targetX;
for (int x = 0; x < width; x++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24));
source += 4;
destination += 4;
source += 4;
destination += 4;
}
}
}
/// <inheritdoc />
protected override void CopyToZYX(PixelRow<Color, uint> row, int sourceY, int width)
protected override void CopyToZYX(PixelArea<Color, uint> area, int sourceY, int sourceX, int width, int height)
{
byte* source = this.GetRowPointer(sourceY);
byte* destination = row.PixelBase;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
source += 4;
destination += 3;
byte* source = this.GetRowPointer(sourceY + y) + sourceX;
byte* destination = area.PixelBase + (y * area.RowByteCount);
for (int x = 0; x < width; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
source += 4;
destination += 3;
}
}
}
/// <inheritdoc />
protected override void CopyToZYXW(PixelRow<Color, uint> row, int sourceY, int width)
protected override void CopyToZYXW(PixelArea<Color, uint> area, int sourceY, int sourceX, int width, int height)
{
byte* source = this.GetRowPointer(sourceY);
byte* destination = row.PixelBase;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
byte* source = this.GetRowPointer(sourceY + y) + sourceX;
byte* destination = area.PixelBase + (y * area.RowByteCount);
for (int x = 0; x < width; x++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
}
}
}
}

8
tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

@ -71,7 +71,7 @@ namespace ImageSharp.Tests
byte blue = 3;
byte alpha = 255;
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(1, ComponentOrder.ZYX))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(1, ComponentOrder.ZYX))
{
row.Bytes[0] = blue;
row.Bytes[1] = green;
@ -99,7 +99,7 @@ namespace ImageSharp.Tests
byte blue = 3;
byte alpha = 4;
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(1, ComponentOrder.ZYXW))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(1, ComponentOrder.ZYXW))
{
row.Bytes[0] = blue;
row.Bytes[1] = green;
@ -127,7 +127,7 @@ namespace ImageSharp.Tests
byte green = 2;
byte blue = 3;
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(1, ComponentOrder.ZYX))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(1, ComponentOrder.ZYX))
{
pixels[0, 0] = (TColor) (object) new Color(red, green, blue);
@ -151,7 +151,7 @@ namespace ImageSharp.Tests
byte blue = 3;
byte alpha = 4;
using (PixelRow<TColor, TPacked> row = new PixelRow<TColor, TPacked>(1, ComponentOrder.ZYXW))
using (PixelArea<TColor, TPacked> row = new PixelArea<TColor, TPacked>(1, ComponentOrder.ZYXW))
{
pixels[0, 0] = (TColor) (object) new Color(red, green, blue, alpha);

Loading…
Cancel
Save