22// Licensed under the Apache License, Version 2.0.
33
44using System ;
5+ using System . Linq ;
56using System . Runtime . InteropServices ;
67
78using SixLabors . ImageSharp . Memory ;
@@ -40,23 +41,66 @@ public static Configuration GetConfiguration(this ImageFrame source)
4041 => GetConfiguration ( ( IConfigurationProvider ) source ) ;
4142
4243 /// <summary>
43- /// Gets the configuration .
44+ /// Gets the configuration.
4445 /// </summary>
4546 /// <param name="source">The source image</param>
4647 /// <returns>Returns the bounds of the image</returns>
4748 private static Configuration GetConfiguration ( IConfigurationProvider source )
4849 => source ? . Configuration ?? Configuration . Default ;
4950
5051 /// <summary>
51- /// Gets the representation of the pixels as a <see cref="Span {T}"/> of contiguous memory in the source image's pixel format
52- /// stored in row major order.
52+ /// Gets the representation of the pixels as a <see cref="IMemoryGroup {T}"/> containing the backing pixel data of the image
53+ /// stored in row major order, as a list of contiguous <see cref="Memory{T}"/> blocks in the source image's pixel format .
5354 /// </summary>
55+ /// <param name="source">The source image.</param>
5456 /// <typeparam name="TPixel">The type of the pixel.</typeparam>
55- /// <param name="source">The source.</param>
57+ /// <returns>The <see cref="IMemoryGroup{T}"/>.</returns>
58+ /// <remarks>
59+ /// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers,
60+ /// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>.
61+ /// </remarks>
62+ public static IMemoryGroup < TPixel > GetPixelMemoryGroup < TPixel > ( this ImageFrame < TPixel > source )
63+ where TPixel : struct , IPixel < TPixel >
64+ => source ? . PixelBuffer . FastMemoryGroup . View ?? throw new ArgumentNullException ( nameof ( source ) ) ;
65+
66+ /// <summary>
67+ /// Gets the representation of the pixels as a <see cref="IMemoryGroup{T}"/> containing the backing pixel data of the image
68+ /// stored in row major order, as a list of contiguous <see cref="Memory{T}"/> blocks in the source image's pixel format.
69+ /// </summary>
70+ /// <param name="source">The source image.</param>
71+ /// <typeparam name="TPixel">The type of the pixel.</typeparam>
72+ /// <returns>The <see cref="IMemoryGroup{T}"/>.</returns>
73+ /// <remarks>
74+ /// Certain Image Processors may invalidate the returned <see cref="IMemoryGroup{T}"/> and all it's buffers,
75+ /// therefore it's not recommended to mutate the image while holding a reference to it's <see cref="IMemoryGroup{T}"/>.
76+ /// </remarks>
77+ public static IMemoryGroup < TPixel > GetPixelMemoryGroup < TPixel > ( this Image < TPixel > source )
78+ where TPixel : struct , IPixel < TPixel >
79+ => source ? . Frames . RootFrame . GetPixelMemoryGroup ( ) ?? throw new ArgumentNullException ( nameof ( source ) ) ;
80+
81+ /// <summary>
82+ /// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format
83+ /// stored in row major order, if the backing buffer is contiguous.
84+ /// </summary>
85+ /// <typeparam name="TPixel">The type of the pixel.</typeparam>
86+ /// <param name="source">The source image.</param>
5687 /// <returns>The <see cref="Span{TPixel}"/></returns>
88+ /// <exception cref="InvalidOperationException">Thrown when the backing buffer is discontiguous.</exception>
89+ [ Obsolete (
90+ @"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!" ) ]
5791 public static Span < TPixel > GetPixelSpan < TPixel > ( this ImageFrame < TPixel > source )
5892 where TPixel : struct , IPixel < TPixel >
59- => source . GetPixelMemory ( ) . Span ;
93+ {
94+ Guard . NotNull ( source , nameof ( source ) ) ;
95+
96+ IMemoryGroup < TPixel > mg = source . GetPixelMemoryGroup ( ) ;
97+ if ( mg . Count > 1 )
98+ {
99+ throw new InvalidOperationException ( $ "GetPixelSpan is invalid, since the backing buffer of this { source . Width } x{ source . Height } sized image is discontiguous!") ;
100+ }
101+
102+ return mg . Single ( ) . Span ;
103+ }
60104
61105 /// <summary>
62106 /// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory in the source image's pixel format
@@ -65,9 +109,16 @@ public static Span<TPixel> GetPixelSpan<TPixel>(this ImageFrame<TPixel> source)
65109 /// <typeparam name="TPixel">The type of the pixel.</typeparam>
66110 /// <param name="source">The source.</param>
67111 /// <returns>The <see cref="Span{TPixel}"/></returns>
112+ /// <exception cref="InvalidOperationException">Thrown when the backing buffer is discontiguous.</exception>
113+ [ Obsolete (
114+ @"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!" ) ]
68115 public static Span < TPixel > GetPixelSpan < TPixel > ( this Image < TPixel > source )
69116 where TPixel : struct , IPixel < TPixel >
70- => source . Frames . RootFrame . GetPixelSpan ( ) ;
117+ {
118+ Guard . NotNull ( source , nameof ( source ) ) ;
119+
120+ return source . Frames . RootFrame . GetPixelSpan ( ) ;
121+ }
71122
72123 /// <summary>
73124 /// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
@@ -79,7 +130,13 @@ public static Span<TPixel> GetPixelSpan<TPixel>(this Image<TPixel> source)
79130 /// <returns>The <see cref="Span{TPixel}"/></returns>
80131 public static Span < TPixel > GetPixelRowSpan < TPixel > ( this ImageFrame < TPixel > source , int rowIndex )
81132 where TPixel : struct , IPixel < TPixel >
82- => source . PixelBuffer . GetRowSpan ( rowIndex ) ;
133+ {
134+ Guard . NotNull ( source , nameof ( source ) ) ;
135+ Guard . MustBeGreaterThanOrEqualTo ( rowIndex , 0 , nameof ( rowIndex ) ) ;
136+ Guard . MustBeLessThan ( rowIndex , source . Height , nameof ( rowIndex ) ) ;
137+
138+ return source . PixelBuffer . GetRowSpan ( rowIndex ) ;
139+ }
83140
84141 /// <summary>
85142 /// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
@@ -91,58 +148,12 @@ public static Span<TPixel> GetPixelRowSpan<TPixel>(this ImageFrame<TPixel> sourc
91148 /// <returns>The <see cref="Span{TPixel}"/></returns>
92149 public static Span < TPixel > GetPixelRowSpan < TPixel > ( this Image < TPixel > source , int rowIndex )
93150 where TPixel : struct , IPixel < TPixel >
94- => source . Frames . RootFrame . GetPixelRowSpan ( rowIndex ) ;
95-
96- /// <summary>
97- /// Returns a reference to the 0th element of the Pixel buffer,
98- /// allowing direct manipulation of pixel data through unsafe operations.
99- /// The pixel buffer is a contiguous memory area containing Width*Height TPixel elements laid out in row-major order.
100- /// </summary>
101- /// <typeparam name="TPixel">The Pixel format.</typeparam>
102- /// <param name="source">The source image frame</param>
103- /// <returns>A pinnable reference the first root of the pixel buffer.</returns>
104- [ Obsolete ( "This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!" ) ]
105- public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer < TPixel > ( this ImageFrame < TPixel > source )
106- where TPixel : struct , IPixel < TPixel >
107- => ref DangerousGetPinnableReferenceToPixelBuffer ( ( IPixelSource < TPixel > ) source ) ;
108-
109- /// <summary>
110- /// Returns a reference to the 0th element of the Pixel buffer,
111- /// allowing direct manipulation of pixel data through unsafe operations.
112- /// The pixel buffer is a contiguous memory area containing Width*Height TPixel elements laid out in row-major order.
113- /// </summary>
114- /// <typeparam name="TPixel">The Pixel format.</typeparam>
115- /// <param name="source">The source image</param>
116- /// <returns>A pinnable reference the first root of the pixel buffer.</returns>
117- [ Obsolete ( "This method will be removed in our next release! Please use MemoryMarshal.GetReference(source.GetPixelSpan())!" ) ]
118- public static ref TPixel DangerousGetPinnableReferenceToPixelBuffer < TPixel > ( this Image < TPixel > source )
119- where TPixel : struct , IPixel < TPixel >
120- => ref source . Frames . RootFrame . DangerousGetPinnableReferenceToPixelBuffer ( ) ;
121-
122- /// <summary>
123- /// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
124- /// stored in row major order.
125- /// </summary>
126- /// <typeparam name="TPixel">The Pixel format.</typeparam>
127- /// <param name="source">The source <see cref="ImageFrame{TPixel}"/></param>
128- /// <returns>The <see cref="Memory{T}"/></returns>
129- internal static Memory < TPixel > GetPixelMemory < TPixel > ( this ImageFrame < TPixel > source )
130- where TPixel : struct , IPixel < TPixel >
131151 {
132- return source . PixelBuffer . MemorySource . Memory ;
133- }
152+ Guard . NotNull ( source , nameof ( source ) ) ;
153+ Guard . MustBeGreaterThanOrEqualTo ( rowIndex , 0 , nameof ( rowIndex ) ) ;
154+ Guard . MustBeLessThan ( rowIndex , source . Height , nameof ( rowIndex ) ) ;
134155
135- /// <summary>
136- /// Gets the representation of the pixels as a <see cref="Memory{T}"/> of contiguous memory in the source image's pixel format
137- /// stored in row major order.
138- /// </summary>
139- /// <typeparam name="TPixel">The Pixel format.</typeparam>
140- /// <param name="source">The source <see cref="Image{TPixel}"/></param>
141- /// <returns>The <see cref="Memory{T}"/></returns>
142- internal static Memory < TPixel > GetPixelMemory < TPixel > ( this Image < TPixel > source )
143- where TPixel : struct , IPixel < TPixel >
144- {
145- return source . Frames . RootFrame . GetPixelMemory ( ) ;
156+ return source . Frames . RootFrame . PixelBuffer . GetRowSpan ( rowIndex ) ;
146157 }
147158
148159 /// <summary>
@@ -153,9 +164,15 @@ internal static Memory<TPixel> GetPixelMemory<TPixel>(this Image<TPixel> source)
153164 /// <param name="source">The source.</param>
154165 /// <param name="rowIndex">The row.</param>
155166 /// <returns>The <see cref="Span{TPixel}"/></returns>
156- internal static Memory < TPixel > GetPixelRowMemory < TPixel > ( this ImageFrame < TPixel > source , int rowIndex )
167+ public static Memory < TPixel > GetPixelRowMemory < TPixel > ( this ImageFrame < TPixel > source , int rowIndex )
157168 where TPixel : struct , IPixel < TPixel >
158- => source . PixelBuffer . GetRowMemory ( rowIndex ) ;
169+ {
170+ Guard . NotNull ( source , nameof ( source ) ) ;
171+ Guard . MustBeGreaterThanOrEqualTo ( rowIndex , 0 , nameof ( rowIndex ) ) ;
172+ Guard . MustBeLessThan ( rowIndex , source . Height , nameof ( rowIndex ) ) ;
173+
174+ return source . PixelBuffer . GetSafeRowMemory ( rowIndex ) ;
175+ }
159176
160177 /// <summary>
161178 /// Gets the representation of the pixels as <see cref="Span{T}"/> of of contiguous memory
@@ -165,9 +182,15 @@ internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this ImageFrame<TPixel>
165182 /// <param name="source">The source.</param>
166183 /// <param name="rowIndex">The row.</param>
167184 /// <returns>The <see cref="Span{TPixel}"/></returns>
168- internal static Memory < TPixel > GetPixelRowMemory < TPixel > ( this Image < TPixel > source , int rowIndex )
185+ public static Memory < TPixel > GetPixelRowMemory < TPixel > ( this Image < TPixel > source , int rowIndex )
169186 where TPixel : struct , IPixel < TPixel >
170- => source . Frames . RootFrame . GetPixelRowMemory ( rowIndex ) ;
187+ {
188+ Guard . NotNull ( source , nameof ( source ) ) ;
189+ Guard . MustBeGreaterThanOrEqualTo ( rowIndex , 0 , nameof ( rowIndex ) ) ;
190+ Guard . MustBeLessThan ( rowIndex , source . Height , nameof ( rowIndex ) ) ;
191+
192+ return source . Frames . RootFrame . PixelBuffer . GetSafeRowMemory ( rowIndex ) ;
193+ }
171194
172195 /// <summary>
173196 /// Gets the <see cref="MemoryAllocator"/> assigned to 'source'.
@@ -176,15 +199,5 @@ internal static Memory<TPixel> GetPixelRowMemory<TPixel>(this Image<TPixel> sour
176199 /// <returns>Returns the configuration.</returns>
177200 internal static MemoryAllocator GetMemoryAllocator ( this IConfigurationProvider source )
178201 => GetConfiguration ( source ) . MemoryAllocator ;
179-
180- /// <summary>
181- /// Returns a reference to the 0th element of the Pixel buffer.
182- /// Such a reference can be used for pinning but must never be dereferenced.
183- /// </summary>
184- /// <param name="source">The source image frame</param>
185- /// <returns>A reference to the element.</returns>
186- private static ref TPixel DangerousGetPinnableReferenceToPixelBuffer < TPixel > ( IPixelSource < TPixel > source )
187- where TPixel : struct , IPixel < TPixel >
188- => ref MemoryMarshal . GetReference ( source . PixelBuffer . GetSpan ( ) ) ;
189202 }
190203}
0 commit comments