22// Licensed under the Six Labors Split License.
33
44using System . Runtime . InteropServices ;
5- using SixLabors . ImageSharp . Memory ;
65using SixLabors . ImageSharp . PixelFormats ;
76
87namespace SixLabors . ImageSharp ;
@@ -25,6 +24,27 @@ public static Image<TPixel> LoadPixelData<TPixel>(ReadOnlySpan<TPixel> data, int
2524 where TPixel : unmanaged, IPixel < TPixel >
2625 => LoadPixelData ( Configuration . Default , data , width , height ) ;
2726
27+ /// <summary>
28+ /// Create a new instance of the <see cref="Image{TPixel}"/> class from raw <typeparamref name="TPixel"/> data
29+ /// using <paramref name="rowStride"/> pixels between source row starts.
30+ /// </summary>
31+ /// <param name="data">The readonly span containing image data.</param>
32+ /// <param name="width">The width of the final image.</param>
33+ /// <param name="height">The height of the final image.</param>
34+ /// <param name="rowStride">The number of pixels between row starts in <paramref name="data"/>.</param>
35+ /// <typeparam name="TPixel">The pixel format.</typeparam>
36+ /// <exception cref="ArgumentOutOfRangeException">
37+ /// <paramref name="width"/> or <paramref name="height"/> is not positive,
38+ /// or <paramref name="rowStride"/> is less than <paramref name="width"/>.
39+ /// </exception>
40+ /// <exception cref="ArgumentException">
41+ /// <paramref name="data"/> is smaller than <c>((height - 1) * rowStride) + width</c>.
42+ /// </exception>
43+ /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
44+ public static Image < TPixel > LoadPixelData < TPixel > ( ReadOnlySpan < TPixel > data , int width , int height , int rowStride )
45+ where TPixel : unmanaged, IPixel < TPixel >
46+ => LoadPixelData ( Configuration . Default , data , width , height , rowStride ) ;
47+
2848 /// <summary>
2949 /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given readonly span of bytes in <typeparamref name="TPixel"/> format.
3050 /// </summary>
@@ -38,6 +58,28 @@ public static Image<TPixel> LoadPixelData<TPixel>(ReadOnlySpan<byte> data, int w
3858 where TPixel : unmanaged, IPixel < TPixel >
3959 => LoadPixelData < TPixel > ( Configuration . Default , data , width , height ) ;
4060
61+ /// <summary>
62+ /// Create a new instance of the <see cref="Image{TPixel}"/> class from a readonly span of bytes in
63+ /// <typeparamref name="TPixel"/> format using <paramref name="rowStrideInBytes"/> bytes between source row starts.
64+ /// </summary>
65+ /// <param name="data">The readonly span containing image data.</param>
66+ /// <param name="width">The width of the final image.</param>
67+ /// <param name="height">The height of the final image.</param>
68+ /// <param name="rowStrideInBytes">The number of bytes between row starts in <paramref name="data"/>.</param>
69+ /// <typeparam name="TPixel">The pixel format.</typeparam>
70+ /// <exception cref="ArgumentOutOfRangeException">
71+ /// <paramref name="width"/> or <paramref name="height"/> is not positive,
72+ /// or <paramref name="rowStrideInBytes"/> resolves to fewer than <paramref name="width"/> pixels.
73+ /// </exception>
74+ /// <exception cref="ArgumentException">
75+ /// <paramref name="rowStrideInBytes"/> is not divisible by the pixel size,
76+ /// or <paramref name="data"/> is smaller than the required strided image length.
77+ /// </exception>
78+ /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
79+ public static Image < TPixel > LoadPixelData < TPixel > ( ReadOnlySpan < byte > data , int width , int height , int rowStrideInBytes )
80+ where TPixel : unmanaged, IPixel < TPixel >
81+ => LoadPixelData < TPixel > ( Configuration . Default , data , width , height , rowStrideInBytes ) ;
82+
4183 /// <summary>
4284 /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given readonly span of bytes in <typeparamref name="TPixel"/> format.
4385 /// </summary>
@@ -53,6 +95,40 @@ public static Image<TPixel> LoadPixelData<TPixel>(Configuration configuration, R
5395 where TPixel : unmanaged, IPixel < TPixel >
5496 => LoadPixelData ( configuration , MemoryMarshal . Cast < byte , TPixel > ( data ) , width , height ) ;
5597
98+ /// <summary>
99+ /// Create a new instance of the <see cref="Image{TPixel}"/> class from a readonly span of bytes in
100+ /// <typeparamref name="TPixel"/> format using <paramref name="rowStrideInBytes"/> bytes between source row starts.
101+ /// </summary>
102+ /// <param name="configuration">The configuration for the decoder.</param>
103+ /// <param name="data">The readonly span containing image data.</param>
104+ /// <param name="width">The width of the final image.</param>
105+ /// <param name="height">The height of the final image.</param>
106+ /// <param name="rowStrideInBytes">The number of bytes between row starts in <paramref name="data"/>.</param>
107+ /// <typeparam name="TPixel">The pixel format.</typeparam>
108+ /// <exception cref="ArgumentNullException">The configuration is null.</exception>
109+ /// <exception cref="ArgumentOutOfRangeException">
110+ /// <paramref name="width"/> or <paramref name="height"/> is not positive,
111+ /// or <paramref name="rowStrideInBytes"/> resolves to fewer than <paramref name="width"/> pixels.
112+ /// </exception>
113+ /// <exception cref="ArgumentException">
114+ /// <paramref name="rowStrideInBytes"/> is not divisible by the pixel size,
115+ /// or <paramref name="data"/> is smaller than the required strided image length.
116+ /// </exception>
117+ /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
118+ public static Image < TPixel > LoadPixelData < TPixel > (
119+ Configuration configuration ,
120+ ReadOnlySpan < byte > data ,
121+ int width ,
122+ int height ,
123+ int rowStrideInBytes )
124+ where TPixel : unmanaged, IPixel < TPixel >
125+ {
126+ Guard . NotNull ( configuration , nameof ( configuration ) ) ;
127+
128+ int rowStride = GetPixelRowStrideFromByteStride < TPixel > ( width , rowStrideInBytes , nameof ( rowStrideInBytes ) ) ;
129+ return LoadPixelData ( configuration , MemoryMarshal . Cast < byte , TPixel > ( data ) , width , height , rowStride ) ;
130+ }
131+
56132 /// <summary>
57133 /// Create a new instance of the <see cref="Image{TPixel}"/> class from the raw <typeparamref name="TPixel"/> data.
58134 /// </summary>
@@ -66,20 +142,42 @@ public static Image<TPixel> LoadPixelData<TPixel>(Configuration configuration, R
66142 /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
67143 public static Image < TPixel > LoadPixelData < TPixel > ( Configuration configuration , ReadOnlySpan < TPixel > data , int width , int height )
68144 where TPixel : unmanaged, IPixel < TPixel >
145+ => LoadPixelData ( configuration , data , width , height , width ) ;
146+
147+ /// <summary>
148+ /// Create a new instance of the <see cref="Image{TPixel}"/> class from raw <typeparamref name="TPixel"/> data
149+ /// using <paramref name="rowStride"/> pixels between source row starts.
150+ /// </summary>
151+ /// <param name="configuration">The configuration for the decoder.</param>
152+ /// <param name="data">The readonly span containing the image pixel data.</param>
153+ /// <param name="width">The width of the final image.</param>
154+ /// <param name="height">The height of the final image.</param>
155+ /// <param name="rowStride">The number of pixels between row starts in <paramref name="data"/>.</param>
156+ /// <exception cref="ArgumentNullException">The configuration is null.</exception>
157+ /// <exception cref="ArgumentOutOfRangeException">
158+ /// <paramref name="width"/> or <paramref name="height"/> is not positive,
159+ /// or <paramref name="rowStride"/> is less than <paramref name="width"/>.
160+ /// </exception>
161+ /// <exception cref="ArgumentException">
162+ /// <paramref name="data"/> is smaller than <c>((height - 1) * rowStride) + width</c>.
163+ /// </exception>
164+ /// <typeparam name="TPixel">The pixel format.</typeparam>
165+ /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
166+ public static Image < TPixel > LoadPixelData < TPixel > (
167+ Configuration configuration ,
168+ ReadOnlySpan < TPixel > data ,
169+ int width ,
170+ int height ,
171+ int rowStride )
172+ where TPixel : unmanaged, IPixel < TPixel >
69173 {
70174 Guard . NotNull ( configuration , nameof ( configuration ) ) ;
71-
72- if ( data . IsEmpty )
73- {
74- throw new ArgumentException ( "Pixel data cannot be empty." , nameof ( data ) ) ;
75- }
76-
77- int count = width * height ;
78- Guard . MustBeGreaterThanOrEqualTo ( data . Length , count , nameof ( data ) ) ;
175+ ValidateWrapMemoryStride ( width , height , rowStride , nameof ( rowStride ) ) ;
176+ long requiredLength = GetRequiredLength ( width , height , rowStride ) ;
177+ Guard . MustBeGreaterThanOrEqualTo ( data . Length , requiredLength , nameof ( data ) ) ;
79178
80179 Image < TPixel > image = new ( configuration , width , height ) ;
81- data = data [ ..count ] ;
82- data . CopyTo ( image . Frames . RootFrame . PixelBuffer . FastMemoryGroup ) ;
180+ image . Frames . RootFrame . PixelBuffer . CopyFrom ( data , rowStride ) ;
83181
84182 return image ;
85183 }
0 commit comments