Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
PixelBuffer.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 using System;
24 using System.IO;
25 using SiliconStudio.Core;
26 
27 namespace SiliconStudio.Paradox.Graphics
28 {
29  /// <summary>
30  /// An unmanaged buffer of pixels.
31  /// </summary>
32  public sealed class PixelBuffer
33  {
34  private int width;
35 
36  private int height;
37 
38  private PixelFormat format;
39 
40  private int rowStride;
41 
42  private int bufferStride;
43 
44  private readonly IntPtr dataPointer;
45 
46  private int pixelSize;
47 
48  /// <summary>
49  /// True when RowStride == sizeof(pixelformat) * width
50  /// </summary>
51  private bool isStrictRowStride;
52 
53  /// <summary>
54  /// Initializes a new instance of the <see cref="PixelBuffer" /> struct.
55  /// </summary>
56  /// <param name="width">The width.</param>
57  /// <param name="height">The height.</param>
58  /// <param name="format">The format.</param>
59  /// <param name="rowStride">The row pitch.</param>
60  /// <param name="bufferStride">The slice pitch.</param>
61  /// <param name="dataPointer">The pixels.</param>
62  public PixelBuffer(int width, int height, PixelFormat format, int rowStride, int bufferStride, IntPtr dataPointer)
63  {
64  if (dataPointer == IntPtr.Zero)
65  throw new ArgumentException("Pointer cannot be equal to IntPtr.Zero", "dataPointer");
66 
67  this.width = width;
68  this.height = height;
69  this.format = format;
70  this.rowStride = rowStride;
71  this.bufferStride = bufferStride;
72  this.dataPointer = dataPointer;
73  this.pixelSize = format.SizeInBytes();
74  this.isStrictRowStride = (pixelSize * width) == rowStride;
75  }
76 
77  /// <summary>
78  /// Gets the width.
79  /// </summary>
80  /// <value>The width.</value>
81  public int Width { get { return width; } }
82 
83  /// <summary>
84  /// Gets the height.
85  /// </summary>
86  /// <value>The height.</value>
87  public int Height { get { return height; } }
88 
89  /// <summary>
90  /// Gets the format.
91  /// </summary>
92  /// <value>The format.</value>
93  public PixelFormat Format { get { return format; } }
94 
95  /// <summary>
96  /// Gets the pixel size in bytes.
97  /// </summary>
98  /// <value>The pixel size in bytes.</value>
99  public int PixelSize { get { return this.pixelSize; } }
100 
101  /// <summary>
102  /// Gets the row stride in number of bytes.
103  /// </summary>
104  /// <value>The row stride in number of bytes.</value>
105  public int RowStride { get { return this.rowStride; } }
106 
107  /// <summary>
108  /// Gets the total size in bytes of this pixel buffer.
109  /// </summary>
110  /// <value>The size in bytes of the pixel buffer.</value>
111  public int BufferStride { get { return this.bufferStride; } }
112 
113  /// <summary>
114  /// Gets the pointer to the pixel buffer.
115  /// </summary>
116  /// <value>The pointer to the pixel buffer.</value>
117  public IntPtr DataPointer { get { return this.dataPointer; } }
118 
119  /// <summary>
120  /// Copies this pixel buffer to a destination pixel buffer.
121  /// </summary>
122  /// <param name="pixelBuffer">The destination pixel buffer.</param>
123  /// <remarks>
124  /// The destination pixel buffer must have exactly the same dimensions (width, height) and format than this instance.
125  /// Destination buffer can have different row stride.
126  /// </remarks>
127  public unsafe void CopyTo(PixelBuffer pixelBuffer)
128  {
129  // Check that buffers are identical
130  if (this.Width != pixelBuffer.Width
131  || this.Height != pixelBuffer.Height
132  || this.Format != pixelBuffer.Format)
133  {
134  throw new ArgumentException("Invalid destination pixelBufferArray. Mush have same Width, Height and Format", "pixelBuffer");
135  }
136 
137  // If buffers have same size, than we can copy it directly
138  if (this.BufferStride == pixelBuffer.BufferStride)
139  {
140  Utilities.CopyMemory(pixelBuffer.DataPointer, this.DataPointer, this.BufferStride);
141  }
142  else
143  {
144  var srcPointer = (byte*)this.DataPointer;
145  var dstPointer = (byte*)pixelBuffer.DataPointer;
146  var rowStride = Math.Min(RowStride, pixelBuffer.RowStride);
147 
148  // Copy per scanline
149  for(int i = 0; i < Height; i++)
150  {
151  Utilities.CopyMemory(new IntPtr(dstPointer), new IntPtr(srcPointer), rowStride);
152  srcPointer += this.RowStride;
153  dstPointer += pixelBuffer.RowStride;
154  }
155  }
156  }
157 
158  /// <summary>
159  /// Saves this pixel buffer to a stream.
160  /// </summary>
161  /// <param name="imageStream">The destination stream.</param>
162  /// <param name="fileType">Specify the output format.</param>
163  /// <remarks>This method support the following format: <c>dds, bmp, jpg, png, gif, tiff, wmp, tga</c>.</remarks>
164  public void Save(Stream imageStream, ImageFileType fileType)
165  {
166  var description = new ImageDescription()
167  {
168  Width = this.width,
169  Height = this.height,
170  Depth = 1,
171  ArraySize = 1,
172  Dimension = TextureDimension.Texture2D,
173  Format = this.format,
174  MipLevels = 1,
175  };
176  Image.Save(new [] {this}, 1, description, imageStream, fileType);
177  }
178 
179  /// <summary>
180  /// Gets the pixel value at a specified position.
181  /// </summary>
182  /// <typeparam name="T">Type of the pixel data</typeparam>
183  /// <param name="x">The x-coordinate.</param>
184  /// <param name="y">The y-coordinate.</param>
185  /// <returns>The pixel value.</returns>
186  /// <remarks>
187  /// Caution, this method doesn't check bounding.
188  /// </remarks>
189  public unsafe T GetPixel<T>(int x, int y) where T : struct
190  {
191  return Utilities.Read<T>(new IntPtr(((byte*)this.DataPointer + RowStride * y + x * PixelSize)));
192  }
193 
194  /// <summary>
195  /// Gets the pixel value at a specified position.
196  /// </summary>
197  /// <typeparam name="T">Type of the pixel data</typeparam>
198  /// <param name="x">The x-coordinate.</param>
199  /// <param name="y">The y-coordinate.</param>
200  /// <param name="value">The pixel value.</param>
201  /// <remarks>
202  /// Caution, this method doesn't check bounding.
203  /// </remarks>
204  public unsafe void SetPixel<T>(int x, int y, T value) where T : struct
205  {
206  Utilities.Write(new IntPtr((byte*)this.DataPointer + RowStride * y + x * PixelSize), ref value);
207  }
208 
209  /// <summary>
210  /// Gets scanline pixels from the buffer.
211  /// </summary>
212  /// <typeparam name="T">Type of the pixel data</typeparam>
213  /// <param name="yOffset">The y line offset.</param>
214  /// <returns>Scanline pixels from the buffer</returns>
215  /// <exception cref="System.ArgumentException">If the sizeof(T) is an invalid size</exception>
216  /// <remarks>
217  /// This method is working on a row basis. The <see cref="yOffset"/> is specifying the first row to get
218  /// the pixels from.
219  /// </remarks>
220  public T[] GetPixels<T>(int yOffset = 0) where T : struct
221  {
222  var sizeOfOutputPixel = Utilities.SizeOf<T>();
223  var totalSize = Width * Height * pixelSize;
224  if ((totalSize % sizeOfOutputPixel) != 0)
225  throw new ArgumentException(string.Format("Invalid sizeof(T), not a multiple of current size [{0}]in bytes ", totalSize));
226 
227  var buffer = new T[totalSize / sizeOfOutputPixel];
228  GetPixels(buffer, yOffset);
229  return buffer;
230  }
231 
232  /// <summary>
233  /// Gets scanline pixels from the buffer.
234  /// </summary>
235  /// <typeparam name="T">Type of the pixel data</typeparam>
236  /// <param name="pixels">An allocated scanline pixel buffer</param>
237  /// <param name="yOffset">The y line offset.</param>
238  /// <returns>Scanline pixels from the buffer</returns>
239  /// <exception cref="System.ArgumentException">If the sizeof(T) is an invalid size</exception>
240  /// <remarks>
241  /// This method is working on a row basis. The <see cref="yOffset"/> is specifying the first row to get
242  /// the pixels from.
243  /// </remarks>
244  public void GetPixels<T>(T[] pixels, int yOffset = 0) where T : struct
245  {
246  GetPixels(pixels, yOffset, 0, pixels.Length);
247  }
248 
249  /// <summary>
250  /// Gets scanline pixels from the buffer.
251  /// </summary>
252  /// <typeparam name="T">Type of the pixel data</typeparam>
253  /// <param name="pixels">An allocated scanline pixel buffer</param>
254  /// <param name="yOffset">The y line offset.</param>
255  /// <param name="pixelIndex">Offset into the destination <see cref="pixels"/> buffer.</param>
256  /// <param name="pixelCount">Number of pixels to write into the destination <see cref="pixels"/> buffer.</param>
257  /// <exception cref="System.ArgumentException">If the sizeof(T) is an invalid size</exception>
258  /// <remarks>
259  /// This method is working on a row basis. The <see cref="yOffset"/> is specifying the first row to get
260  /// the pixels from.
261  /// </remarks>
262  public unsafe void GetPixels<T>(T[] pixels, int yOffset, int pixelIndex, int pixelCount) where T : struct
263  {
264  var pixelPointer = (byte*)this.DataPointer + yOffset * rowStride;
265  if (isStrictRowStride)
266  {
267  Utilities.Read(new IntPtr(pixelPointer), pixels, 0, pixelCount);
268  }
269  else
270  {
271  var sizeOfOutputPixel = Utilities.SizeOf<T>() * pixelCount;
272  var sizePerWidth = sizeOfOutputPixel / Width;
273  var remainingPixels = sizeOfOutputPixel % Width;
274  for(int i = 0; i < sizePerWidth; i++)
275  {
276  Utilities.Read(new IntPtr(pixelPointer), pixels, pixelIndex, Width);
277  pixelPointer += rowStride;
278  pixelIndex += Width;
279  }
280  if (remainingPixels > 0)
281  {
282  Utilities.Read(new IntPtr(pixelPointer), pixels, pixelIndex, remainingPixels);
283  }
284  }
285  }
286 
287  /// <summary>
288  /// Sets scanline pixels to the buffer.
289  /// </summary>
290  /// <typeparam name="T">Type of the pixel data</typeparam>
291  /// <param name="sourcePixels">Source pixel buffer</param>
292  /// <param name="yOffset">The y line offset.</param>
293  /// <exception cref="System.ArgumentException">If the sizeof(T) is an invalid size</exception>
294  /// <remarks>
295  /// This method is working on a row basis. The <see cref="yOffset"/> is specifying the first row to get
296  /// the pixels from.
297  /// </remarks>
298  public void SetPixels<T>(T[] sourcePixels, int yOffset = 0) where T : struct
299  {
300  SetPixels(sourcePixels, yOffset, 0, sourcePixels.Length);
301  }
302 
303  /// <summary>
304  /// Sets scanline pixels to the buffer.
305  /// </summary>
306  /// <typeparam name="T">Type of the pixel data</typeparam>
307  /// <param name="sourcePixels">Source pixel buffer</param>
308  /// <param name="yOffset">The y line offset.</param>
309  /// <param name="pixelIndex">Offset into the source <see cref="sourcePixels"/> buffer.</param>
310  /// <param name="pixelCount">Number of pixels to write into the source <see cref="sourcePixels"/> buffer.</param>
311  /// <exception cref="System.ArgumentException">If the sizeof(T) is an invalid size</exception>
312  /// <remarks>
313  /// This method is working on a row basis. The <see cref="yOffset"/> is specifying the first row to get
314  /// the pixels from.
315  /// </remarks>
316  public unsafe void SetPixels<T>(T[] sourcePixels, int yOffset, int pixelIndex, int pixelCount) where T : struct
317  {
318  var pixelPointer = (byte*)this.DataPointer + yOffset * rowStride;
319  if (isStrictRowStride)
320  {
321  Utilities.Write(new IntPtr(pixelPointer), sourcePixels, 0, pixelCount);
322  }
323  else
324  {
325  var sizeOfOutputPixel = Utilities.SizeOf<T>() * pixelCount;
326  var sizePerWidth = sizeOfOutputPixel / Width;
327  var remainingPixels = sizeOfOutputPixel % Width;
328  for (int i = 0; i < sizePerWidth; i++)
329  {
330  Utilities.Write(new IntPtr(pixelPointer), sourcePixels, pixelIndex, Width);
331  pixelPointer += rowStride;
332  pixelIndex += Width;
333  }
334  if (remainingPixels > 0)
335  {
336  Utilities.Write(new IntPtr(pixelPointer), sourcePixels, pixelIndex, remainingPixels);
337  }
338  }
339  }
340  }
341 }
int RowStride
Gets the row stride in number of bytes.
Definition: PixelBuffer.cs:105
ImageFileType
Image file format used by Image.Save(string,SiliconStudio.Paradox.Graphics.ImageFileType) ...
PixelBuffer(int width, int height, PixelFormat format, int rowStride, int bufferStride, IntPtr dataPointer)
Initializes a new instance of the PixelBuffer struct.
Definition: PixelBuffer.cs:62
void Save(Stream imageStream, ImageFileType fileType)
Saves this pixel buffer to a stream.
Definition: PixelBuffer.cs:164
unsafe void CopyTo(PixelBuffer pixelBuffer)
Copies this pixel buffer to a destination pixel buffer.
Definition: PixelBuffer.cs:127
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
_In_ size_t pixelSize
Definition: DirectXTexP.h:116
int BufferStride
Gets the total size in bytes of this pixel buffer.
Definition: PixelBuffer.cs:111
IntPtr DataPointer
Gets the pointer to the pixel buffer.
Definition: PixelBuffer.cs:117
PixelFormat Format
Gets the format.
Definition: PixelBuffer.cs:93
An unmanaged buffer of pixels.
Definition: PixelBuffer.cs:32
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32