|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 6.8 KiB |
@ -0,0 +1,144 @@ |
|||
// <copyright file="MathF.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions.
|
|||
/// </summary>
|
|||
// ReSharper disable InconsistentNaming
|
|||
internal static class MathF |
|||
{ |
|||
/// <summary>
|
|||
/// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.
|
|||
/// </summary>
|
|||
public const float PI = (float)Math.PI; |
|||
|
|||
/// <summary>Returns the absolute value of a single-precision floating-point number.</summary>
|
|||
/// <param name="f">A number that is greater than or equal to <see cref="F:System.Single.MinValue" />, but less than or equal to <see cref="F:System.Single.MaxValue" />.</param>
|
|||
/// <returns>A single-precision floating-point number, x, such that 0 ≤ x ≤<see cref="F:System.Single.MaxValue" />.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Abs(float f) |
|||
{ |
|||
return Math.Abs(f); |
|||
} |
|||
|
|||
/// <summary>Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number.</summary>
|
|||
/// <param name="f">A single-precision floating-point number. </param>
|
|||
/// <returns>The smallest integral value that is greater than or equal to <paramref name="f" />.
|
|||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|||
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|||
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Ceiling(float f) |
|||
{ |
|||
return (float)Math.Ceiling(f); |
|||
} |
|||
|
|||
/// <summary>Returns e raised to the specified power.</summary>
|
|||
/// <param name="f">A number specifying a power.</param>
|
|||
/// <returns>
|
|||
/// The number e raised to the power <paramref name="f" />.
|
|||
/// If <paramref name="f" /> equals <see cref="F:System.Single.NaN" /> or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|||
/// If <paramref name="f" /> equals <see cref="F:System.Single.NegativeInfinity" />, 0 is returned.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Exp(float f) |
|||
{ |
|||
return (float)Math.Exp(f); |
|||
} |
|||
|
|||
/// <summary>Returns the largest integer less than or equal to the specified single-precision floating-point number.</summary>
|
|||
/// <param name="f">A single-precision floating-point number. </param>
|
|||
/// <returns>The largest integer less than or equal to <paramref name="f" />.
|
|||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|||
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Floor(float f) |
|||
{ |
|||
return (float)Math.Floor(f); |
|||
} |
|||
|
|||
/// <summary>Returns the larger of two single-precision floating-point numbers.</summary>
|
|||
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
|
|||
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
|
|||
/// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is larger.
|
|||
/// If <paramref name="val1" />, or <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are
|
|||
/// equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Max(float val1, float val2) |
|||
{ |
|||
return Math.Max(val1, val2); |
|||
} |
|||
|
|||
/// <summary>Returns the smaller of two single-precision floating-point numbers.</summary>
|
|||
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
|
|||
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
|
|||
/// <returns>Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is smaller.
|
|||
/// If <paramref name="val1" />, <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are equal
|
|||
/// to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Min(float val1, float val2) |
|||
{ |
|||
return Math.Min(val1, val2); |
|||
} |
|||
|
|||
/// <summary>Returns a specified number raised to the specified power.</summary>
|
|||
/// <param name="x">A single-precision floating-point number to be raised to a power. </param>
|
|||
/// <param name="y">A single-precision floating-point number that specifies a power. </param>
|
|||
/// <returns>The number <paramref name="x" /> raised to the power <paramref name="y" />.</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Pow(float x, float y) |
|||
{ |
|||
return (float)Math.Pow(x, y); |
|||
} |
|||
|
|||
/// <summary>Rounds a single-precision floating-point value to the nearest integral value.</summary>
|
|||
/// <param name="f">A single-precision floating-point number to be rounded. </param>
|
|||
/// <returns>
|
|||
/// The integer nearest <paramref name="f" />.
|
|||
/// If the fractional component of <paramref name="f" /> is halfway between two integers, one of which is even and the other odd, then the even number is returned.
|
|||
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Round(float f) |
|||
{ |
|||
return (float)Math.Round(f); |
|||
} |
|||
|
|||
/// <summary>Returns the sine of the specified angle.</summary>
|
|||
/// <param name="f">An angle, measured in radians. </param>
|
|||
/// <returns>
|
|||
/// The sine of <paramref name="f" />.
|
|||
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
|
|||
/// or <see cref="F:System.Single.PositiveInfinity" />, this method returns <see cref="F:System.Single.NaN" />.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Sin(float f) |
|||
{ |
|||
return (float)Math.Sin(f); |
|||
} |
|||
|
|||
/// <summary>Returns the square root of a specified number.</summary>
|
|||
/// <param name="f">The number whose square root is to be found. </param>
|
|||
/// <returns>
|
|||
/// One of the values in the following table.
|
|||
/// <paramref name="f" /> parameter Return value Zero or positive The positive square root of <paramref name="f" />.
|
|||
/// Negative <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.NaN" />
|
|||
/// <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.PositiveInfinity" />
|
|||
/// <see cref="F:System.Single.PositiveInfinity" />
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static float Sqrt(float f) |
|||
{ |
|||
return (float)Math.Sqrt(f); |
|||
} |
|||
} |
|||
} |
|||
@ -1,143 +0,0 @@ |
|||
// <copyright file="BufferPointer{T}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Provides access to elements in an array from a given position.
|
|||
/// This type shares many similarities with corefx System.Span<T> but there are significant differences in it's functionalities and semantics:
|
|||
/// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays
|
|||
/// - It's possible to retrieve a reference to the array (<see cref="Array"/>) so we can pass it to API-s like <see cref="Marshal.Copy(byte[], int, IntPtr, int)"/>
|
|||
/// - There is no bounds checking for performance reasons. Therefore we don't need to store length. (However this could be added as DEBUG-only feature.)
|
|||
/// This makes <see cref="BufferPointer{T}"/> an unsafe type!
|
|||
/// - Currently the arrays provided to BufferPointer need to be pinned. This behaviour could be changed using C#7 features.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of elements of the array</typeparam>
|
|||
internal unsafe struct BufferPointer<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferPointer{T}"/> struct from a pinned array and an offset.
|
|||
/// </summary>
|
|||
/// <param name="array">The pinned array</param>
|
|||
/// <param name="pointerToArray">Pointer to the beginning of array</param>
|
|||
/// <param name="offset">The offset inside the array</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferPointer(T[] array, void* pointerToArray, int offset) |
|||
{ |
|||
DebugGuard.NotNull(array, nameof(array)); |
|||
|
|||
this.Array = array; |
|||
this.Offset = offset; |
|||
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * offset); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferPointer{T}"/> struct from a pinned array.
|
|||
/// </summary>
|
|||
/// <param name="array">The pinned array</param>
|
|||
/// <param name="pointerToArray">Pointer to the start of 'array'</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferPointer(T[] array, void* pointerToArray) |
|||
{ |
|||
DebugGuard.NotNull(array, nameof(array)); |
|||
|
|||
this.Array = array; |
|||
this.Offset = 0; |
|||
this.PointerAtOffset = (IntPtr)pointerToArray; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the array
|
|||
/// </summary>
|
|||
public T[] Array { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the offset inside <see cref="Array"/>
|
|||
/// </summary>
|
|||
public int Offset { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the offset inside <see cref="Array"/> in bytes.
|
|||
/// </summary>
|
|||
public int ByteOffset => this.Offset * Unsafe.SizeOf<T>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the pointer to the offseted array position
|
|||
/// </summary>
|
|||
public IntPtr PointerAtOffset { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Convertes <see cref="BufferPointer{T}"/> instance to a raw 'void*' pointer
|
|||
/// </summary>
|
|||
/// <param name="bufferPointer">The <see cref="BufferPointer{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator void*(BufferPointer<T> bufferPointer) |
|||
{ |
|||
return (void*)bufferPointer.PointerAtOffset; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts <see cref="BufferPointer{T}"/> instance to a raw 'byte*' pointer
|
|||
/// </summary>
|
|||
/// <param name="bufferPointer">The <see cref="BufferPointer{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator byte*(BufferPointer<T> bufferPointer) |
|||
{ |
|||
return (byte*)bufferPointer.PointerAtOffset; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts <see cref="BufferPointer{T}"/> instance to <see cref="BufferPointer{Byte}"/>
|
|||
/// setting it's <see cref="Offset"/> and <see cref="PointerAtOffset"/> to correct values.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="BufferPointer{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator BufferPointer<byte>(BufferPointer<T> source) |
|||
{ |
|||
BufferPointer<byte> result = default(BufferPointer<byte>); |
|||
result.Array = Unsafe.As<byte[]>(source.Array); |
|||
result.Offset = source.Offset * Unsafe.SizeOf<T>(); |
|||
result.PointerAtOffset = source.PointerAtOffset; |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Forms a slice out of the given BufferPointer, beginning at 'offset'.
|
|||
/// </summary>
|
|||
/// <param name="offset">The offset in number of elements</param>
|
|||
/// <returns>The offseted (sliced) BufferPointer</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferPointer<T> Slice(int offset) |
|||
{ |
|||
BufferPointer<T> result = default(BufferPointer<T>); |
|||
result.Array = this.Array; |
|||
result.Offset = this.Offset + offset; |
|||
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * offset); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clears `count` elements beginning from the pointed position.
|
|||
/// </summary>
|
|||
/// <param name="count">The number of elements to clear</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Clear(int count) |
|||
{ |
|||
if (count < 256) |
|||
{ |
|||
Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferPointer.USizeOf<T>(count)); |
|||
} |
|||
else |
|||
{ |
|||
System.Array.Clear(this.Array, this.Offset, count); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,237 @@ |
|||
// <copyright file="BufferSpan{T}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Represents a contiguous region of a pinned managed array.
|
|||
/// The array is usually owned by a <see cref="PinnedBuffer{T}"/> instance.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <see cref="BufferSpan{T}"/> is very similar to corefx System.Span<T>, and we try to maintain a compatible API.
|
|||
/// There are several differences though:
|
|||
/// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays.
|
|||
/// - It's possible to retrieve a reference to the array (<see cref="Array"/>) so we can pass it to API-s like <see cref="Marshal.Copy(byte[], int, IntPtr, int)"/>
|
|||
/// - It's possible to retrieve the pinned pointer. This enables optimized (unchecked) unsafe operations.
|
|||
/// - There is no bounds checking for performance reasons, only in debug mode. This makes <see cref="BufferSpan{T}"/> an unsafe type!
|
|||
/// </remarks>
|
|||
/// <typeparam name="T">The type of elements of the array</typeparam>
|
|||
internal unsafe struct BufferSpan<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
|
|||
/// </summary>
|
|||
/// <param name="array">The pinned array</param>
|
|||
/// <param name="pointerToArray">Pointer to the beginning of the array</param>
|
|||
/// <param name="start">The index at which to begin the span.</param>
|
|||
/// <param name="length">The length</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferSpan(T[] array, void* pointerToArray, int start, int length) |
|||
{ |
|||
GuardArrayAndPointer(array, pointerToArray); |
|||
|
|||
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start)); |
|||
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length)); |
|||
|
|||
this.Array = array; |
|||
this.Length = length; |
|||
this.Start = start; |
|||
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
|
|||
/// </summary>
|
|||
/// <param name="array">The pinned array</param>
|
|||
/// <param name="pointerToArray">Pointer to the beginning of the array</param>
|
|||
/// <param name="start">The index at which to begin the span.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferSpan(T[] array, void* pointerToArray, int start) |
|||
{ |
|||
GuardArrayAndPointer(array, pointerToArray); |
|||
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start)); |
|||
|
|||
this.Array = array; |
|||
this.Length = array.Length - start; |
|||
this.Start = start; |
|||
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array.
|
|||
/// </summary>
|
|||
/// <param name="array">The pinned array</param>
|
|||
/// <param name="pointerToArray">Pointer to the start of 'array'</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferSpan(T[] array, void* pointerToArray) |
|||
{ |
|||
GuardArrayAndPointer(array, pointerToArray); |
|||
|
|||
this.Array = array; |
|||
this.Start = 0; |
|||
this.Length = array.Length; |
|||
this.PointerAtOffset = (IntPtr)pointerToArray; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the backing array
|
|||
/// </summary>
|
|||
public T[] Array { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the length of the <see cref="BufferSpan{T}"/>
|
|||
/// </summary>
|
|||
public int Length { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the start inside <see cref="Array"/>
|
|||
/// </summary>
|
|||
public int Start { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the start inside <see cref="Array"/> in bytes.
|
|||
/// </summary>
|
|||
public int ByteOffset => this.Start * Unsafe.SizeOf<T>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets the pointer to the offseted array position
|
|||
/// </summary>
|
|||
public IntPtr PointerAtOffset { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Returns a reference to specified element of the span.
|
|||
/// </summary>
|
|||
/// <param name="index">The index</param>
|
|||
/// <returns>The reference to the specified element</returns>
|
|||
public ref T this[int index] |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); |
|||
|
|||
byte* ptr = (byte*)this.PointerAtOffset + BufferSpan.SizeOf<T>(index); |
|||
return ref Unsafe.AsRef<T>(ptr); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Convertes <see cref="BufferSpan{T}"/> instance to a raw 'void*' pointer
|
|||
/// </summary>
|
|||
/// <param name="bufferSpan">The <see cref="BufferSpan{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator void*(BufferSpan<T> bufferSpan) |
|||
{ |
|||
return (void*)bufferSpan.PointerAtOffset; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts <see cref="BufferSpan{T}"/> instance to a raw 'byte*' pointer
|
|||
/// </summary>
|
|||
/// <param name="bufferSpan">The <see cref="BufferSpan{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator byte*(BufferSpan<T> bufferSpan) |
|||
{ |
|||
return (byte*)bufferSpan.PointerAtOffset; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
|
|||
/// setting it's <see cref="Start"/> and <see cref="PointerAtOffset"/> to correct values.
|
|||
/// </summary>
|
|||
/// <param name="source">The <see cref="BufferSpan{T}"/> to convert</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static explicit operator BufferSpan<byte>(BufferSpan<T> source) |
|||
{ |
|||
BufferSpan<byte> result = default(BufferSpan<byte>); |
|||
result.Array = Unsafe.As<byte[]>(source.Array); |
|||
result.Start = source.Start * Unsafe.SizeOf<T>(); |
|||
result.PointerAtOffset = source.PointerAtOffset; |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
|
|||
/// </summary>
|
|||
/// <param name="start">TThe index at which to begin this slice.</param>
|
|||
/// <returns>The offseted (sliced) BufferSpan</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferSpan<T> Slice(int start) |
|||
{ |
|||
DebugGuard.MustBeLessThan(start, this.Length, nameof(start)); |
|||
|
|||
BufferSpan<T> result = default(BufferSpan<T>); |
|||
result.Array = this.Array; |
|||
result.Start = this.Start + start; |
|||
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start); |
|||
result.Length = this.Length - start; |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
|
|||
/// </summary>
|
|||
/// <param name="start">The index at which to begin this slice.</param>
|
|||
/// <param name="length">The desired length for the slice (exclusive).</param>
|
|||
/// <returns>The sliced BufferSpan</returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public BufferSpan<T> Slice(int start, int length) |
|||
{ |
|||
DebugGuard.MustBeLessThanOrEqualTo(start, this.Length, nameof(start)); |
|||
DebugGuard.MustBeLessThanOrEqualTo(length, this.Length - start, nameof(length)); |
|||
|
|||
BufferSpan<T> result = default(BufferSpan<T>); |
|||
result.Array = this.Array; |
|||
result.Start = this.Start + start; |
|||
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start); |
|||
result.Length = length; |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clears `count` elements from the beginning of the span.
|
|||
/// </summary>
|
|||
/// <param name="count">The number of elements to clear</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Clear(int count) |
|||
{ |
|||
DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count)); |
|||
|
|||
if (count < 256) |
|||
{ |
|||
Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferSpan.USizeOf<T>(count)); |
|||
} |
|||
else |
|||
{ |
|||
System.Array.Clear(this.Array, this.Start, count); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clears the the span
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void Clear() |
|||
{ |
|||
this.Clear(this.Length); |
|||
} |
|||
|
|||
[Conditional("DEBUG")] |
|||
private static void GuardArrayAndPointer(T[] array, void* pointerToArray) |
|||
{ |
|||
DebugGuard.NotNull(array, nameof(array)); |
|||
DebugGuard.IsFalse( |
|||
pointerToArray == (void*)0, |
|||
nameof(pointerToArray), |
|||
"pointerToArray should not be null pointer!"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// <copyright file="IPinnedImageBuffer{T}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// An interface that represents a pinned buffer of value type objects
|
|||
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The value type.</typeparam>
|
|||
internal interface IPinnedImageBuffer<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the width.
|
|||
/// </summary>
|
|||
int Width { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the height.
|
|||
/// </summary>
|
|||
int Height { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
|
|||
/// </summary>
|
|||
BufferSpan<T> Span { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
// <copyright file="PinnedImageBufferExtensions{T}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Defines extension methods for <see cref="IPinnedImageBuffer{T}"/>.
|
|||
/// </summary>
|
|||
internal static class PinnedImageBufferExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
|
|||
/// </summary>
|
|||
/// <param name="buffer">The buffer</param>
|
|||
/// <param name="x">The x coordinate (position in the row)</param>
|
|||
/// <param name="y">The y (row) coordinate</param>
|
|||
/// <typeparam name="T">The element type</typeparam>
|
|||
/// <returns>The <see cref="BufferSpan{T}"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static BufferSpan<T> GetRowSpan<T>(this IPinnedImageBuffer<T> buffer, int x, int y) |
|||
where T : struct |
|||
{ |
|||
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
|
|||
/// </summary>
|
|||
/// <param name="buffer">The buffer</param>
|
|||
/// <param name="y">The y (row) coordinate</param>
|
|||
/// <typeparam name="T">The element type</typeparam>
|
|||
/// <returns>The <see cref="BufferSpan{T}"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static BufferSpan<T> GetRowSpan<T>(this IPinnedImageBuffer<T> buffer, int y) |
|||
where T : struct |
|||
{ |
|||
return buffer.Span.Slice(y * buffer.Width, buffer.Width); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
// <copyright file="PinnedImageBuffer{T}.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Represents a pinned buffer of value type objects
|
|||
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The value type.</typeparam>
|
|||
internal class PinnedImageBuffer<T> : PinnedBuffer<T>, IPinnedImageBuffer<T> |
|||
where T : struct |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="width">The number of elements in a row</param>
|
|||
/// <param name="height">The number of rows</param>
|
|||
public PinnedImageBuffer(int width, int height) |
|||
: base(width * height) |
|||
{ |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="array">The array to pin</param>
|
|||
/// <param name="width">The number of elements in a row</param>
|
|||
/// <param name="height">The number of rows</param>
|
|||
public PinnedImageBuffer(T[] array, int width, int height) |
|||
: base(array, width * height) |
|||
{ |
|||
this.Width = width; |
|||
this.Height = height; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public int Width { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public int Height { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a reference to the element at the specified position.
|
|||
/// </summary>
|
|||
/// <param name="x">The x coordinate (row)</param>
|
|||
/// <param name="y">The y coordinate (position at row)</param>
|
|||
/// <returns>A reference to the element.</returns>
|
|||
public ref T this[int x, int y] |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
return ref this.Array[(this.Width * y) + x]; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a clean instance of <see cref="PinnedImageBuffer{T}"/> initializing it's elements with 'default(T)'.
|
|||
/// </summary>
|
|||
/// <param name="width">The number of elements in a row</param>
|
|||
/// <param name="height">The number of rows</param>
|
|||
/// <returns>The <see cref="PinnedBuffer{T}"/> instance</returns>
|
|||
public static PinnedImageBuffer<T> CreateClean(int width, int height) |
|||
{ |
|||
PinnedImageBuffer<T> buffer = new PinnedImageBuffer<T>(width, height); |
|||
buffer.Clear(); |
|||
return buffer; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
// <copyright file="OrderedDither4x4.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Dithering.Ordered |
|||
{ |
|||
/// <summary>
|
|||
/// The base class for performing ordered ditheroing using a 4x4 matrix.
|
|||
/// </summary>
|
|||
public abstract class OrderedDither4x4 : IOrderedDither |
|||
{ |
|||
/// <summary>
|
|||
/// The dithering matrix
|
|||
/// </summary>
|
|||
private Fast2DArray<byte> matrix; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="OrderedDither4x4"/> class.
|
|||
/// </summary>
|
|||
/// <param name="matrix">The thresholding matrix. </param>
|
|||
internal OrderedDither4x4(Fast2DArray<byte> matrix) |
|||
{ |
|||
this.matrix = matrix; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void Dither<TColor>(PixelAccessor<TColor> pixels, TColor source, TColor upper, TColor lower, byte[] bytes, int index, int x, int y, int width, int height) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
// TODO: This doesn't really cut it for me.
|
|||
// I'd rather be using float but we need to add some sort of movalization vector methods to all IPixel implementations
|
|||
// before we can do that as the vectors all cover different ranges.
|
|||
source.ToXyzwBytes(bytes, 0); |
|||
pixels[x, y] = this.matrix[y % 3, x % 3] >= bytes[index] ? lower : upper; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
// <copyright file="EndianBitConverter.Conversion.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
|
|||
/// </summary>
|
|||
internal abstract partial class EndianBitConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Converts the specified double-precision floating point number to a
|
|||
/// 64-bit signed integer. Note: the endianness of this converter does not
|
|||
/// affect the returned value.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert. </param>
|
|||
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
|
|||
public unsafe long DoubleToInt64Bits(double value) |
|||
{ |
|||
return *((long*)&value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the specified 64-bit signed integer to a double-precision
|
|||
/// floating point number. Note: the endianness of this converter does not
|
|||
/// affect the returned value.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert. </param>
|
|||
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
|
|||
public unsafe double Int64BitsToDouble(long value) |
|||
{ |
|||
return *((double*)&value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the specified single-precision floating point number to a
|
|||
/// 32-bit signed integer. Note: the endianness of this converter does not
|
|||
/// affect the returned value.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert. </param>
|
|||
/// <returns>A 32-bit signed integer whose value is equivalent to value.</returns>
|
|||
public unsafe int SingleToInt32Bits(float value) |
|||
{ |
|||
return *((int*)&value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts the specified 32-bit signed integer to a single-precision floating point
|
|||
/// number. Note: the endianness of this converter does not
|
|||
/// affect the returned value.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert. </param>
|
|||
/// <returns>A single-precision floating point number whose value is equivalent to value.</returns>
|
|||
public unsafe float Int32BitsToSingle(int value) |
|||
{ |
|||
return *((float*)&value); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,145 @@ |
|||
// <copyright file="EndianBitConverter.CopyBytes.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
|
|||
/// </summary>
|
|||
internal abstract partial class EndianBitConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Copies the specified 16-bit signed integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public abstract void CopyBytes(short value, byte[] buffer, int index); |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified 32-bit signed integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public abstract void CopyBytes(int value, byte[] buffer, int index); |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified 64-bit signed integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public abstract void CopyBytes(long value, byte[] buffer, int index); |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified 16-bit unsigned integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public void CopyBytes(ushort value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(unchecked((short)value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified 32-bit unsigned integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public void CopyBytes(uint value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(unchecked((int)value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified 64-bit unsigned integer value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public void CopyBytes(ulong value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(unchecked((long)value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified Boolean value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">A Boolean value.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public void CopyBytes(bool value, byte[] buffer, int index) |
|||
{ |
|||
CheckByteArgument(buffer, index, 1); |
|||
buffer[index] = value ? (byte)1 : (byte)0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified Unicode character value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">A character to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public void CopyBytes(char value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(unchecked((short)value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified double-precision floating point value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public unsafe void CopyBytes(double value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(*((long*)&value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified single-precision floating point value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public unsafe void CopyBytes(float value, byte[] buffer, int index) |
|||
{ |
|||
this.CopyBytes(*((int*)&value), buffer, index); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Copies the specified decimal value into the specified byte array,
|
|||
/// beginning at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="value">A character to convert.</param>
|
|||
/// <param name="buffer">The byte array to copy the bytes into</param>
|
|||
/// <param name="index">The first index into the array to copy the bytes into</param>
|
|||
public unsafe void CopyBytes(decimal value, byte[] buffer, int index) |
|||
{ |
|||
CheckByteArgument(buffer, index, 16); |
|||
|
|||
int* pvalue = (int*)&value; |
|||
this.CopyBytes(pvalue[0], buffer, index); |
|||
this.CopyBytes(pvalue[1], buffer, index + 4); |
|||
this.CopyBytes(pvalue[2], buffer, index + 8); |
|||
this.CopyBytes(pvalue[3], buffer, index + 12); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,139 @@ |
|||
// <copyright file="EndianBitConverter.GetBytes.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
|
|||
/// </summary>
|
|||
internal abstract partial class EndianBitConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Returns the specified 16-bit signed integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 2.</returns>
|
|||
public byte[] GetBytes(short value) |
|||
{ |
|||
byte[] result = new byte[2]; |
|||
this.CopyBytes(value, result, 0); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified 32-bit signed integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 4.</returns>
|
|||
public byte[] GetBytes(int value) |
|||
{ |
|||
byte[] result = new byte[4]; |
|||
this.CopyBytes(value, result, 0); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified 64-bit signed integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 8.</returns>
|
|||
public byte[] GetBytes(long value) |
|||
{ |
|||
byte[] result = new byte[8]; |
|||
this.CopyBytes(value, result, 0); |
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified 16-bit unsigned integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 2.</returns>
|
|||
public byte[] GetBytes(ushort value) |
|||
{ |
|||
return this.GetBytes(unchecked((short)value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified 32-bit unsigned integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 4.</returns>
|
|||
public byte[] GetBytes(uint value) |
|||
{ |
|||
return this.GetBytes(unchecked((int)value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified 64-bit unsigned integer value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 8.</returns>
|
|||
public byte[] GetBytes(ulong value) |
|||
{ |
|||
return this.GetBytes(unchecked((long)value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified Boolean value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">A Boolean value.</param>
|
|||
/// <returns>An array of bytes with length 1.</returns>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
public byte[] GetBytes(bool value) |
|||
{ |
|||
return new byte[1] { value ? (byte)1 : (byte)0 }; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified Unicode character value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">A character to convert.</param>
|
|||
/// <returns>An array of bytes with length 2.</returns>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
public byte[] GetBytes(char value) |
|||
{ |
|||
return this.GetBytes((short)value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified double-precision floating point value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 8.</returns>
|
|||
public unsafe byte[] GetBytes(double value) |
|||
{ |
|||
return this.GetBytes(*((long*)&value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified single-precision floating point value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 4.</returns>
|
|||
public unsafe byte[] GetBytes(float value) |
|||
{ |
|||
return this.GetBytes(*((int*)&value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns the specified decimal value as an array of bytes.
|
|||
/// </summary>
|
|||
/// <param name="value">The number to convert.</param>
|
|||
/// <returns>An array of bytes with length 16.</returns>
|
|||
public byte[] GetBytes(decimal value) |
|||
{ |
|||
byte[] result = new byte[16]; |
|||
this.CopyBytes(value, result, 0); |
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,141 @@ |
|||
// <copyright file="EndianBitConverter.ToType.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
|
|||
/// </summary>
|
|||
internal abstract partial class EndianBitConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 16-bit signed integer formed by two bytes beginning at startIndex.</returns>
|
|||
public abstract short ToInt16(byte[] value, int startIndex); |
|||
|
|||
/// <summary>
|
|||
/// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 32-bit signed integer formed by four bytes beginning at startIndex.</returns>
|
|||
public abstract int ToInt32(byte[] value, int startIndex); |
|||
|
|||
/// <summary>
|
|||
/// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 64-bit signed integer formed by eight bytes beginning at startIndex.</returns>
|
|||
public abstract long ToInt64(byte[] value, int startIndex); |
|||
|
|||
/// <summary>
|
|||
/// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
|
|||
public ushort ToUInt16(byte[] value, int startIndex) |
|||
{ |
|||
return unchecked((ushort)this.ToInt16(value, startIndex)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
|
|||
public uint ToUInt32(byte[] value, int startIndex) |
|||
{ |
|||
return unchecked((uint)this.ToInt32(value, startIndex)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A 64-bit unsigned integer formed by eight bytes beginning at startIndex.</returns>
|
|||
public ulong ToUInt64(byte[] value, int startIndex) |
|||
{ |
|||
return unchecked((ulong)this.ToInt64(value, startIndex)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a Boolean value converted from one byte at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>true if the byte at startIndex in value is nonzero; otherwise, false.</returns>
|
|||
public bool ToBoolean(byte[] value, int startIndex) |
|||
{ |
|||
CheckByteArgument(value, startIndex, 1); |
|||
return value[startIndex] != 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a Unicode character converted from two bytes at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A character formed by two bytes beginning at startIndex.</returns>
|
|||
public char ToChar(byte[] value, int startIndex) |
|||
{ |
|||
return unchecked((char)this.ToInt16(value, startIndex)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a double-precision floating point number converted from eight bytes
|
|||
/// at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A double precision floating point number formed by eight bytes beginning at startIndex.</returns>
|
|||
public unsafe double ToDouble(byte[] value, int startIndex) |
|||
{ |
|||
long intValue = this.ToInt64(value, startIndex); |
|||
return *((double*)&intValue); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a single-precision floating point number converted from four bytes
|
|||
/// at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A single precision floating point number formed by four bytes beginning at startIndex.</returns>
|
|||
public unsafe float ToSingle(byte[] value, int startIndex) |
|||
{ |
|||
int intValue = this.ToInt32(value, startIndex); |
|||
return *((float*)&intValue); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a decimal value converted from sixteen bytes
|
|||
/// at a specified position in a byte array.
|
|||
/// </summary>
|
|||
/// <param name="value">An array of bytes.</param>
|
|||
/// <param name="startIndex">The starting position within value.</param>
|
|||
/// <returns>A decimal formed by sixteen bytes beginning at startIndex.</returns>
|
|||
public unsafe decimal ToDecimal(byte[] value, int startIndex) |
|||
{ |
|||
CheckByteArgument(value, startIndex, 16); |
|||
|
|||
decimal result = 0m; |
|||
int* presult = (int*)&result; |
|||
presult[0] = this.ToInt32(value, startIndex); |
|||
presult[1] = this.ToInt32(value, startIndex + 4); |
|||
presult[2] = this.ToInt32(value, startIndex + 8); |
|||
presult[3] = this.ToInt32(value, startIndex + 12); |
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// <copyright file="IFileSystem.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System.IO; |
|||
|
|||
#if !NETSTANDARD1_1
|
|||
/// <summary>
|
|||
/// A simple interface representing the filesystem.
|
|||
/// </summary>
|
|||
public interface IFileSystem |
|||
{ |
|||
/// <summary>
|
|||
/// Returns a readable stream as defined by the path.
|
|||
/// </summary>
|
|||
/// <param name="path">Path to the file to open.</param>
|
|||
/// <returns>A stream representing the file to open.</returns>
|
|||
Stream OpenRead(string path); |
|||
|
|||
/// <summary>
|
|||
/// Creates or opens a file and returns it as a writeable stream as defined by the path.
|
|||
/// </summary>
|
|||
/// <param name="path">Path to the file to open.</param>
|
|||
/// <returns>A stream representing the file to open.</returns>
|
|||
Stream Create(string path); |
|||
} |
|||
#endif
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
// <copyright file="LocalFileSystem.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.IO |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
|
|||
#if !NETSTANDARD1_1
|
|||
/// <summary>
|
|||
/// A wrapper around the local File apis.
|
|||
/// </summary>
|
|||
public class LocalFileSystem : IFileSystem |
|||
{ |
|||
/// <inheritdoc/>
|
|||
public Stream OpenRead(string path) |
|||
{ |
|||
return File.OpenRead(path); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public Stream Create(string path) |
|||
{ |
|||
return File.Create(path); |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
// <copyright file="Image.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.IO; |
|||
|
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Create a new instance of the <see cref="Image{TColor}"/> class
|
|||
/// with the height and the width of the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="width">The width of the image in pixels.</param>
|
|||
/// <param name="height">The height of the image in pixels.</param>
|
|||
/// <param name="metadata">The images matadata to preload.</param>
|
|||
/// <param name="configuration">
|
|||
/// The configuration providing initialization code which allows extending the library.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A new <see cref="Image{TColor}"/> unless <typeparamref name="TColor"/> is <see cref="Color"/> in which case it returns <see cref="Image" />
|
|||
/// </returns>
|
|||
internal static Image<TColor> Create<TColor>(int width, int height, ImageMetaData metadata, Configuration configuration) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
if (typeof(TColor) == typeof(Color)) |
|||
{ |
|||
return new Image(width, height, metadata, configuration) as Image<TColor>; |
|||
} |
|||
else |
|||
{ |
|||
return new Image<TColor>(width, height, metadata, configuration); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a new instance of the <see cref="Image{TColor}"/> class
|
|||
/// with the height and the width of the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="width">The width of the image in pixels.</param>
|
|||
/// <param name="height">The height of the image in pixels.</param>
|
|||
/// <param name="configuration">
|
|||
/// The configuration providing initialization code which allows extending the library.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A new <see cref="Image{TColor}"/> unless <typeparamref name="TColor"/> is <see cref="Color"/> in which case it returns <see cref="Image" />
|
|||
/// </returns>
|
|||
internal static Image<TColor> Create<TColor>(int width, int height, Configuration configuration) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Image.Create<TColor>(width, height, null, configuration); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
// <copyright file="Image.Decode.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System.Buffers; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// By reading the header on the provided stream this calculates the images format.
|
|||
/// </summary>
|
|||
/// <param name="stream">The image stream to read the header from.</param>
|
|||
/// <param name="config">The configuration.</param>
|
|||
/// <returns>The image format or null if none found.</returns>
|
|||
private static IImageFormat DiscoverFormat(Stream stream, Configuration config) |
|||
{ |
|||
// This is probably a candidate for making into a public API in the future!
|
|||
int maxHeaderSize = config.MaxHeaderSize; |
|||
if (maxHeaderSize <= 0) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
IImageFormat format; |
|||
byte[] header = ArrayPool<byte>.Shared.Rent(maxHeaderSize); |
|||
try |
|||
{ |
|||
long startPosition = stream.Position; |
|||
stream.Read(header, 0, maxHeaderSize); |
|||
stream.Position = startPosition; |
|||
format = config.ImageFormats.FirstOrDefault(x => x.IsSupportedFileFormat(header)); |
|||
} |
|||
finally |
|||
{ |
|||
ArrayPool<byte>.Shared.Return(header); |
|||
} |
|||
|
|||
return format; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Decodes the image stream to the current image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="stream">The stream.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <param name="config">the configuration.</param>
|
|||
/// <returns>
|
|||
/// The decoded image
|
|||
/// </returns>
|
|||
private static Image<TColor> Decode<TColor>(Stream stream, IDecoderOptions options, Configuration config) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
IImageFormat format = DiscoverFormat(stream, config); |
|||
if (format == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
Image<TColor> img = format.Decoder.Decode<TColor>(config, stream, options); |
|||
img.CurrentImageFormat = format; |
|||
return img; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,212 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] data) |
|||
{ |
|||
return Load(null, data, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] data, IDecoderOptions options) |
|||
{ |
|||
return Load(null, data, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, byte[] data) |
|||
{ |
|||
return Load(config, data, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] data, IImageDecoder decoder) |
|||
{ |
|||
return Load(data, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, byte[] data, IDecoderOptions options) |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(data)) |
|||
{ |
|||
return Load(config, ms, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(data)) |
|||
{ |
|||
return Load(ms, decoder, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(byte[] data) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, data, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(byte[] data, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, data, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, byte[] data) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(config, data, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(byte[] data, IImageDecoder decoder) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(data, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, byte[] data, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(data)) |
|||
{ |
|||
return Load<TColor>(config, ms, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given byte array.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="data">The byte array containing image data.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(byte[] data, IImageDecoder decoder, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
using (MemoryStream ms = new MemoryStream(data)) |
|||
{ |
|||
return Load<TColor>(ms, decoder, options); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,214 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
#if !NETSTANDARD1_1
|
|||
using System; |
|||
using System.IO; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string path) |
|||
{ |
|||
return Load(null, path, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string path, IDecoderOptions options) |
|||
{ |
|||
return Load(null, path, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, string path) |
|||
{ |
|||
return Load(config, path, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string path, IImageDecoder decoder) |
|||
{ |
|||
return Load(path, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options) |
|||
{ |
|||
return new Image(Load<Color>(path, decoder, options)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, string path, IDecoderOptions options) |
|||
{ |
|||
config = config ?? Configuration.Default; |
|||
using (Stream s = config.FileSystem.OpenRead(path)) |
|||
{ |
|||
return Load(config, s, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(string path) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, path, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(string path, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, path, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, string path) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(config, path, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(string path, IImageDecoder decoder) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(path, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, string path, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
config = config ?? Configuration.Default; |
|||
using (Stream s = config.FileSystem.OpenRead(path)) |
|||
{ |
|||
return Load<TColor>(config, s, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given file.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="path">The file path to the image.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(string path, IImageDecoder decoder, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
Configuration config = Configuration.Default; |
|||
using (Stream s = config.FileSystem.OpenRead(path)) |
|||
{ |
|||
return Load<TColor>(s, decoder, options); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|||
@ -0,0 +1,246 @@ |
|||
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
using System.Text; |
|||
using Formats; |
|||
|
|||
/// <summary>
|
|||
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
|
|||
/// packed into a single unsigned integer value.
|
|||
/// </summary>
|
|||
public sealed partial class Image |
|||
{ |
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream) |
|||
{ |
|||
return Load(null, stream, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream, IDecoderOptions options) |
|||
{ |
|||
return Load(null, stream, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, Stream stream) |
|||
{ |
|||
return Load(config, stream, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream, IImageDecoder decoder) |
|||
{ |
|||
return Load(stream, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Configuration config, Stream stream, IDecoderOptions options) |
|||
{ |
|||
Image<Color> image = Load<Color>(config, stream, options); |
|||
|
|||
return image as Image ?? new Image(image); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) |
|||
{ |
|||
Image<Color> image = new Image(Load<Color>(stream, decoder, options)); |
|||
|
|||
return image as Image ?? new Image(image); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Stream stream) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, stream, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Stream stream, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(null, stream, options); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The config for the decoder.</param>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, Stream stream) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(config, stream, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Stream stream, IImageDecoder decoder) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return Load<TColor>(stream, decoder, null); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="decoder">The decoder.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Stream stream, IImageDecoder decoder, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
return WithSeekableStream(stream, s => decoder.Decode<TColor>(Configuration.Default, s, options)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Loads the image from the given stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
/// <param name="config">The configuration options.</param>
|
|||
/// <param name="stream">The stream containing image information.</param>
|
|||
/// <param name="options">The options for the decoder.</param>
|
|||
/// <exception cref="NotSupportedException">
|
|||
/// Thrown if the stream is not readable nor seekable.
|
|||
/// </exception>
|
|||
/// <returns>The image</returns>
|
|||
public static Image<TColor> Load<TColor>(Configuration config, Stream stream, IDecoderOptions options) |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
config = config ?? Configuration.Default; |
|||
|
|||
Image<TColor> img = WithSeekableStream(stream, s => Decode<TColor>(stream, options, config)); |
|||
|
|||
if (img != null) |
|||
{ |
|||
return img; |
|||
} |
|||
|
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.AppendLine("Image cannot be loaded. Available formats:"); |
|||
|
|||
foreach (IImageFormat format in config.ImageFormats) |
|||
{ |
|||
stringBuilder.AppendLine("-" + format); |
|||
} |
|||
|
|||
throw new NotSupportedException(stringBuilder.ToString()); |
|||
} |
|||
|
|||
private static T WithSeekableStream<T>(Stream stream, Func<Stream, T> action) |
|||
{ |
|||
if (!stream.CanRead) |
|||
{ |
|||
throw new NotSupportedException("Cannot read from the stream."); |
|||
} |
|||
|
|||
if (stream.CanSeek) |
|||
{ |
|||
return action(stream); |
|||
} |
|||
else |
|||
{ |
|||
// We want to be able to load images from things like HttpContext.Request.Body
|
|||
using (MemoryStream ms = new MemoryStream()) |
|||
{ |
|||
stream.CopyTo(ms); |
|||
ms.Position = 0; |
|||
|
|||
return action(stream); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||