22// Licensed under the Apache License, Version 2.0.
33
44using System ;
5+ using System . Buffers ;
6+ using System . Diagnostics ;
57using System . Runtime . CompilerServices ;
8+ using System . Runtime . InteropServices ;
69
710using SixLabors . Primitives ;
811
@@ -14,55 +17,135 @@ namespace SixLabors.ImageSharp.Memory
1417 internal static class Buffer2DExtensions
1518 {
1619 /// <summary>
17- /// Gets a <see cref="Span{T}"/> to the backing buffer of <paramref name="buffer"/>.
20+ /// Copy <paramref name="columnCount"/> columns of <paramref name="buffer"/> inplace,
21+ /// from positions starting at <paramref name="sourceIndex"/> to positions at <paramref name="destIndex"/>.
1822 /// </summary>
19- internal static Span < T > GetSpan < T > ( this Buffer2D < T > buffer )
23+ public static unsafe void CopyColumns < T > (
24+ this Buffer2D < T > buffer ,
25+ int sourceIndex ,
26+ int destIndex ,
27+ int columnCount )
2028 where T : struct
2129 {
22- return buffer . MemorySource . GetSpan ( ) ;
30+ DebugGuard . NotNull ( buffer , nameof ( buffer ) ) ;
31+ DebugGuard . MustBeGreaterThanOrEqualTo ( sourceIndex , 0 , nameof ( sourceIndex ) ) ;
32+ DebugGuard . MustBeGreaterThanOrEqualTo ( destIndex , 0 , nameof ( sourceIndex ) ) ;
33+ CheckColumnRegionsDoNotOverlap ( buffer , sourceIndex , destIndex , columnCount ) ;
34+
35+ int elementSize = Unsafe . SizeOf < T > ( ) ;
36+ int width = buffer . Width * elementSize ;
37+ int sOffset = sourceIndex * elementSize ;
38+ int dOffset = destIndex * elementSize ;
39+ long count = columnCount * elementSize ;
40+
41+ Span < byte > span = MemoryMarshal . AsBytes ( buffer . Memory . Span ) ;
42+
43+ fixed ( byte * ptr = span )
44+ {
45+ byte * basePtr = ( byte * ) ptr ;
46+ for ( int y = 0 ; y < buffer . Height ; y ++ )
47+ {
48+ byte * sPtr = basePtr + sOffset ;
49+ byte * dPtr = basePtr + dOffset ;
50+
51+ Buffer . MemoryCopy ( sPtr , dPtr , count , count ) ;
52+
53+ basePtr += width ;
54+ }
55+ }
2356 }
2457
2558 /// <summary>
26- /// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
59+ /// Returns a <see cref="Rectangle"/> representing the full area of the buffer.
60+ /// </summary>
61+ /// <typeparam name="T">The element type</typeparam>
62+ /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
63+ /// <returns>The <see cref="Rectangle"/></returns>
64+ public static Rectangle FullRectangle < T > ( this Buffer2D < T > buffer )
65+ where T : struct
66+ {
67+ return new Rectangle ( 0 , 0 , buffer . Width , buffer . Height ) ;
68+ }
69+
70+ /// <summary>
71+ /// Return a <see cref="BufferArea{T}"/> to the subarea represented by 'rectangle'
72+ /// </summary>
73+ /// <typeparam name="T">The element type</typeparam>
74+ /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
75+ /// <param name="rectangle">The rectangle subarea</param>
76+ /// <returns>The <see cref="BufferArea{T}"/></returns>
77+ public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer , in Rectangle rectangle )
78+ where T : struct =>
79+ new BufferArea < T > ( buffer , rectangle ) ;
80+
81+ public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer , int x , int y , int width , int height )
82+ where T : struct =>
83+ new BufferArea < T > ( buffer , new Rectangle ( x , y , width , height ) ) ;
84+
85+ /// <summary>
86+ /// Return a <see cref="BufferArea{T}"/> to the whole area of 'buffer'
87+ /// </summary>
88+ /// <typeparam name="T">The element type</typeparam>
89+ /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
90+ /// <returns>The <see cref="BufferArea{T}"/></returns>
91+ public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer )
92+ where T : struct =>
93+ new BufferArea < T > ( buffer ) ;
94+
95+ public static BufferArea < T > GetAreaBetweenRows < T > ( this Buffer2D < T > buffer , int minY , int maxY )
96+ where T : struct =>
97+ new BufferArea < T > ( buffer , new Rectangle ( 0 , minY , buffer . Width , maxY - minY ) ) ;
98+
99+ /// <summary>
100+ /// Gets a span for all the pixels in <paramref name="buffer"/> defined by <paramref name="rows"/>
101+ /// </summary>
102+ public static Span < T > GetMultiRowSpan < T > ( this Buffer2D < T > buffer , in RowInterval rows )
103+ where T : struct
104+ {
105+ return buffer . Span . Slice ( rows . Min * buffer . Width , rows . Height * buffer . Width ) ;
106+ }
107+
108+ /// <summary>
109+ /// Gets a <see cref="Memory{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
27110 /// </summary>
28111 /// <param name="buffer">The buffer</param>
29- /// <param name="x">The x coordinate (position in the row)</param>
30112 /// <param name="y">The y (row) coordinate</param>
31113 /// <typeparam name="T">The element type</typeparam>
32114 /// <returns>The <see cref="Span{T}"/></returns>
33115 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
34- public static Span < T > GetRowSpan < T > ( this Buffer2D < T > buffer , int x , int y )
116+ public static Memory < T > GetRowMemory < T > ( this Buffer2D < T > buffer , int y )
35117 where T : struct
36118 {
37- return buffer . GetSpan ( ) . Slice ( ( y * buffer . Width ) + x , buffer . Width - x ) ;
119+ return buffer . MemorySource . Memory . Slice ( y * buffer . Width , buffer . Width ) ;
38120 }
39121
40122 /// <summary>
41- /// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at the first pixel on that row .
123+ /// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x' .
42124 /// </summary>
43125 /// <param name="buffer">The buffer</param>
126+ /// <param name="x">The x coordinate (position in the row)</param>
44127 /// <param name="y">The y (row) coordinate</param>
45128 /// <typeparam name="T">The element type</typeparam>
46129 /// <returns>The <see cref="Span{T}"/></returns>
47130 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
48- public static Span < T > GetRowSpan < T > ( this Buffer2D < T > buffer , int y )
131+ public static Span < T > GetRowSpan < T > ( this Buffer2D < T > buffer , int x , int y )
49132 where T : struct
50133 {
51- return buffer . GetSpan ( ) . Slice ( y * buffer . Width , buffer . Width ) ;
134+ return buffer . GetSpan ( ) . Slice ( ( y * buffer . Width ) + x , buffer . Width - x ) ;
52135 }
53136
54137 /// <summary>
55- /// Gets a <see cref="Memory {T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
138+ /// Gets a <see cref="Span {T}"/> to the row 'y' beginning from the pixel at the first pixel on that row.
56139 /// </summary>
57140 /// <param name="buffer">The buffer</param>
58141 /// <param name="y">The y (row) coordinate</param>
59142 /// <typeparam name="T">The element type</typeparam>
60143 /// <returns>The <see cref="Span{T}"/></returns>
61144 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
62- public static Memory < T > GetRowMemory < T > ( this Buffer2D < T > buffer , int y )
145+ public static Span < T > GetRowSpan < T > ( this Buffer2D < T > buffer , int y )
63146 where T : struct
64147 {
65- return buffer . MemorySource . Memory . Slice ( y * buffer . Width , buffer . Width ) ;
148+ return buffer . GetSpan ( ) . Slice ( y * buffer . Width , buffer . Width ) ;
66149 }
67150
68151 /// <summary>
@@ -78,49 +161,28 @@ public static Size Size<T>(this Buffer2D<T> buffer)
78161 }
79162
80163 /// <summary>
81- /// Returns a <see cref="Rectangle "/> representing the full area of the buffer.
164+ /// Gets a <see cref="Span{T} "/> to the backing buffer of <paramref name=" buffer"/> .
82165 /// </summary>
83- /// <typeparam name="T">The element type</typeparam>
84- /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
85- /// <returns>The <see cref="Rectangle"/></returns>
86- public static Rectangle FullRectangle < T > ( this Buffer2D < T > buffer )
166+ internal static Span < T > GetSpan < T > ( this Buffer2D < T > buffer )
87167 where T : struct
88168 {
89- return new Rectangle ( 0 , 0 , buffer . Width , buffer . Height ) ;
169+ return buffer . MemorySource . GetSpan ( ) ;
90170 }
91171
92- /// <summary>
93- /// Return a <see cref="BufferArea{T}"/> to the subarea represented by 'rectangle'
94- /// </summary>
95- /// <typeparam name="T">The element type</typeparam>
96- /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
97- /// <param name="rectangle">The rectangle subarea</param>
98- /// <returns>The <see cref="BufferArea{T}"/></returns>
99- public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer , in Rectangle rectangle )
100- where T : struct => new BufferArea < T > ( buffer , rectangle ) ;
101-
102- public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer , int x , int y , int width , int height )
103- where T : struct => new BufferArea < T > ( buffer , new Rectangle ( x , y , width , height ) ) ;
104-
105- public static BufferArea < T > GetAreaBetweenRows < T > ( this Buffer2D < T > buffer , int minY , int maxY )
106- where T : struct => new BufferArea < T > ( buffer , new Rectangle ( 0 , minY , buffer . Width , maxY - minY ) ) ;
107-
108- /// <summary>
109- /// Return a <see cref="BufferArea{T}"/> to the whole area of 'buffer'
110- /// </summary>
111- /// <typeparam name="T">The element type</typeparam>
112- /// <param name="buffer">The <see cref="Buffer2D{T}"/></param>
113- /// <returns>The <see cref="BufferArea{T}"/></returns>
114- public static BufferArea < T > GetArea < T > ( this Buffer2D < T > buffer )
115- where T : struct => new BufferArea < T > ( buffer ) ;
116-
117- /// <summary>
118- /// Gets a span for all the pixels in <paramref name="buffer"/> defined by <paramref name="rows"/>
119- /// </summary>
120- public static Span < T > GetMultiRowSpan < T > ( this Buffer2D < T > buffer , in RowInterval rows )
172+ [ Conditional ( "DEBUG" ) ]
173+ private static void CheckColumnRegionsDoNotOverlap < T > (
174+ Buffer2D < T > buffer ,
175+ int sourceIndex ,
176+ int destIndex ,
177+ int columnCount )
121178 where T : struct
122179 {
123- return buffer . Span . Slice ( rows . Min * buffer . Width , rows . Height * buffer . Width ) ;
180+ int minIndex = Math . Min ( sourceIndex , destIndex ) ;
181+ int maxIndex = Math . Max ( sourceIndex , destIndex ) ;
182+ if ( maxIndex < minIndex + columnCount || maxIndex > buffer . Width - columnCount )
183+ {
184+ throw new InvalidOperationException ( "Column regions should not overlap!" ) ;
185+ }
124186 }
125187 }
126188}
0 commit comments