-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
ReadOnlySpan<T>
/ ReadOnlyMemory<T>
overloads
Implements: - `Source.NewFromMemory`, `Image.FindLoadBuffer` and `Image.NewFromBuffer` for `ReadOnlySpan<byte>`. - `Image.NewFromMemory` for `ReadOnlyMemory<T>`. - `Image.NewFromMemoryCopy` for `ReadOnlySpan<T>`.
- Loading branch information
Showing
5 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
#if NET6_0_OR_GREATER | ||
|
||
namespace NetVips | ||
{ | ||
using System; | ||
using System.Runtime.InteropServices; | ||
using Internal; | ||
|
||
/// <summary> | ||
/// Wrap a <see cref="VipsImage"/> object. | ||
/// </summary> | ||
public partial class Image | ||
{ | ||
#region helpers | ||
|
||
/// <summary> | ||
/// Find the name of the load operation vips will use to load a buffer. | ||
/// </summary> | ||
/// <remarks> | ||
/// For example "VipsForeignLoadJpegBuffer". You can use this to work out what | ||
/// options to pass to <see cref="NewFromBuffer(ReadOnlySpan{byte}, string, Enums.Access?, Enums.FailOn?, VOption)"/>. | ||
/// </remarks> | ||
/// <param name="data">The buffer to test.</param> | ||
/// <param name="size">Length of the buffer.</param> | ||
/// <returns>The name of the load operation, or <see langword="null"/>.</returns> | ||
internal static unsafe string FindLoadBuffer(void* data, ulong size) => | ||
Marshal.PtrToStringAnsi(VipsForeign.FindLoadBuffer(data, size)); | ||
|
||
/// <summary> | ||
/// Find the name of the load operation vips will use to load a buffer. | ||
/// </summary> | ||
/// <remarks> | ||
/// For example "VipsForeignLoadJpegBuffer". You can use this to work out what | ||
/// options to pass to <see cref="NewFromBuffer(ReadOnlySpan{byte}, string, Enums.Access?, Enums.FailOn?, VOption)"/>. | ||
/// </remarks> | ||
/// <param name="data">The buffer to test.</param> | ||
/// <returns>The name of the load operation, or <see langword="null"/>.</returns> | ||
public static unsafe string FindLoadBuffer(ReadOnlySpan<byte> data) | ||
{ | ||
fixed (byte* dataFixed = data) | ||
{ | ||
return FindLoadBuffer(dataFixed, (ulong)data.Length); | ||
} | ||
} | ||
|
||
#endregion | ||
|
||
#region constructors | ||
|
||
/// <summary> | ||
/// Load a formatted image from memory. | ||
/// </summary> | ||
/// <remarks> | ||
/// This behaves exactly as <see cref="NewFromFile"/>, but the image is | ||
/// loaded from the memory object rather than from a file. The memory | ||
/// object can be a string or buffer. | ||
/// </remarks> | ||
/// <param name="data">The memory object to load the image from.</param> | ||
/// <param name="strOptions">Load options as a string. Use <see cref="string.Empty"/> for no options.</param> | ||
/// <param name="access">Hint the expected access pattern for the image.</param> | ||
/// <param name="failOn">The type of error that will cause load to fail. By | ||
/// default, loaders are permissive, that is, <see cref="Enums.FailOn.None"/>.</param> | ||
/// <param name="kwargs">Optional options that depend on the load operation.</param> | ||
/// <returns>A new <see cref="Image"/>.</returns> | ||
/// <exception cref="VipsException">If unable to load from <paramref name="data"/>.</exception> | ||
public static unsafe Image NewFromBuffer( | ||
ReadOnlySpan<byte> data, | ||
string strOptions = "", | ||
Enums.Access? access = null, | ||
Enums.FailOn? failOn = null, | ||
VOption kwargs = null) | ||
{ | ||
fixed (byte* dataFixed = data) | ||
{ | ||
var operationName = FindLoadBuffer(dataFixed, (ulong)data.Length); | ||
if (operationName == null) | ||
{ | ||
throw new VipsException("unable to load from buffer"); | ||
} | ||
|
||
var options = new VOption(); | ||
if (kwargs != null) | ||
{ | ||
options.Merge(kwargs); | ||
} | ||
|
||
options.AddIfPresent(nameof(access), access); | ||
options.AddFailOn(failOn); | ||
|
||
options.Add("string_options", strOptions); | ||
|
||
using var blob = Internal.VipsBlob.Copy(dataFixed, (UIntPtr)data.Length); | ||
return Operation.Call(operationName, options, blob) as Image; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Wrap an image around a memory array. | ||
/// </summary> | ||
/// <param name="data">A <see cref="ReadOnlyMemory{T}"/>.</param> | ||
/// <param name="width">Image width in pixels.</param> | ||
/// <param name="height">Image height in pixels.</param> | ||
/// <param name="bands">Number of bands.</param> | ||
/// <param name="format">Band format.</param> | ||
/// <returns>A new <see cref="Image"/>.</returns> | ||
/// <exception cref="VipsException">If unable to make image from <paramref name="data"/>.</exception> | ||
public static unsafe Image NewFromMemory<T>( | ||
ReadOnlyMemory<T> data, | ||
int width, | ||
int height, | ||
int bands, | ||
Enums.BandFormat format) where T : unmanaged | ||
{ | ||
var handle = data.Pin(); | ||
var vi = VipsImage.NewFromMemory(handle.Pointer, (UIntPtr)data.Length, width, height, bands, | ||
format); | ||
|
||
if (vi == IntPtr.Zero) | ||
{ | ||
handle.Dispose(); | ||
|
||
throw new VipsException("unable to make image from memory"); | ||
} | ||
|
||
var image = new Image(vi) { MemoryPressure = data.Length }; | ||
|
||
// Need to release the pinned MemoryHandle when the image is closed. | ||
image.OnPostClose += () => handle.Dispose(); | ||
|
||
return image; | ||
} | ||
|
||
/// <summary> | ||
/// Like <see cref="NewFromMemory{T}(ReadOnlyMemory{T}, int, int, int, Enums.BandFormat)"/>, but | ||
/// for <see cref="ReadOnlySpan{T}"/>, so we must copy as it could be allocated on the stack. | ||
/// </summary> | ||
/// <param name="data">A <see cref="ReadOnlySpan{T}"/>.</param> | ||
/// <param name="width">Image width in pixels.</param> | ||
/// <param name="height">Image height in pixels.</param> | ||
/// <param name="bands">Number of bands.</param> | ||
/// <param name="format">Band format.</param> | ||
/// <returns>A new <see cref="Image"/>.</returns> | ||
/// <exception cref="VipsException">If unable to make image from <paramref name="data"/>.</exception> | ||
public static unsafe Image NewFromMemoryCopy<T>( | ||
ReadOnlySpan<T> data, | ||
int width, | ||
int height, | ||
int bands, | ||
Enums.BandFormat format) where T : unmanaged | ||
{ | ||
fixed (T* dataFixed = data) | ||
{ | ||
var vi = VipsImage.NewFromMemoryCopy(dataFixed, (UIntPtr)data.Length, width, height, bands, format); | ||
|
||
if (vi == IntPtr.Zero) | ||
{ | ||
throw new VipsException("unable to make image from memory"); | ||
} | ||
|
||
return new Image(vi) { MemoryPressure = data.Length }; | ||
} | ||
} | ||
|
||
#endregion | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#if NET6_0_OR_GREATER | ||
|
||
namespace NetVips | ||
{ | ||
using System; | ||
|
||
/// <summary> | ||
/// An input connection. | ||
/// </summary> | ||
public partial class Source | ||
{ | ||
/// <summary> | ||
/// Make a new source from a memory object. | ||
/// </summary> | ||
/// <remarks> | ||
/// Make a new source that is attached to the memory object. For example: | ||
/// <code language="lang-csharp"> | ||
/// using var source = Source.NewFromMemory(data); | ||
/// </code> | ||
/// You can pass this source to (for example) <see cref="Image.NewFromSource"/>. | ||
/// </remarks> | ||
/// <param name="data">The memory object.</param> | ||
/// <returns>A new <see cref="Source"/>.</returns> | ||
/// <exception cref="VipsException">If unable to create a new <see cref="Source"/> from <paramref name="data"/>.</exception> | ||
public static unsafe Source NewFromMemory(ReadOnlySpan<byte> data) | ||
{ | ||
fixed (byte* dataFixed = data) | ||
{ | ||
using var blob = Internal.VipsBlob.Copy(dataFixed, (UIntPtr)data.Length); | ||
var pointer = Internal.VipsSource.NewFromBlob(blob); | ||
|
||
if (pointer == IntPtr.Zero) | ||
{ | ||
throw new VipsException("can't create input source from memory"); | ||
} | ||
|
||
return new Source(pointer); | ||
} | ||
} | ||
} | ||
} | ||
|
||
#endif |