VectSharp  2.2.1
A light library for C# vector graphics
RasterImage.cs
1 /*
2  VectSharp - A light library for C# vector graphics.
3  Copyright (C) 2020-2022 Giorgio Bianchini
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, version 3.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public License
15  along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17 
18 using System;
19 using System.IO;
20 using System.Runtime.InteropServices;
21 
22 namespace VectSharp
23 {
24  /// <summary>
25  /// Represents the pixel format of a raster image.
26  /// </summary>
27  public enum PixelFormats
28  {
29  /// <summary>
30  /// RGB 24bpp format.
31  /// </summary>
32  RGB,
33 
34  /// <summary>
35  /// RGBA 32bpp format.
36  /// </summary>
37  RGBA,
38 
39  /// <summary>
40  /// BGR 24bpp format.
41  /// </summary>
42  BGR,
43 
44  /// <summary>
45  /// BGR 32bpp format.
46  /// </summary>
47  BGRA
48  }
49 
50  /// <summary>
51  /// An <see cref="IDisposable"/> wrapper around an <see cref="IntPtr"/> that frees the allocated memory when it is disposed.
52  /// </summary>
53  public class DisposableIntPtr : IDisposable
54  {
55  /// <summary>
56  /// The pointer to the unmanaged memory.
57  /// </summary>
58  public readonly IntPtr InternalPointer;
59 
60  /// <summary>
61  /// Create a new DisposableIntPtr.
62  /// </summary>
63  /// <param name="pointer">The pointer that should be freed upon disposing of this object.</param>
64  public DisposableIntPtr(IntPtr pointer)
65  {
66  this.InternalPointer = pointer;
67  }
68 
69  private bool disposedValue;
70 
71  ///<inheritdoc/>
72  protected virtual void Dispose(bool disposing)
73  {
74  if (!disposedValue)
75  {
76  Marshal.FreeHGlobal(InternalPointer);
77  disposedValue = true;
78  }
79  }
80 
81  ///<inheritdoc/>
83  {
84  Dispose(disposing: false);
85  }
86 
87  ///<inheritdoc/>
88  public void Dispose()
89  {
90  Dispose(disposing: true);
91  GC.SuppressFinalize(this);
92  }
93  }
94 
95  /// <summary>
96  /// Represents a raster image, created from raw pixel data. Consider using the derived classes included in the NuGet package "VectSharp.MuPDFUtils" if you need to load a raster image from a file or a <see cref="Stream"/>.
97  /// </summary>
98  public class RasterImage : IDisposable
99  {
100  /// <summary>
101  /// The memory address of the image pixel data.
102  /// </summary>
103  public IntPtr ImageDataAddress { get; protected set; }
104 
105  /// <summary>
106  /// An <see cref="IDisposable"/> that will be disposed when the image is disposed.
107  /// </summary>
108  public IDisposable DataHolder { get; protected set; }
109 
110  /// <summary>
111  /// A univocal identifier for this image.
112  /// </summary>
113  public string Id { get; protected set; }
114 
115  /// <summary>
116  /// Determines whether the image has an alpha channel.
117  /// </summary>
118  public bool HasAlpha { get; protected set; }
119 
120  /// <summary>
121  /// The width in pixels of the image.
122  /// </summary>
123  public int Width { get; protected set; }
124 
125  /// <summary>
126  /// The height in pixels of the image.
127  /// </summary>
128  public int Height { get; protected set; }
129 
130  /// <summary>
131  /// Determines whether the image should be interpolated when it is resized.
132  /// </summary>
133  public bool Interpolate { get; protected set; }
134 
135  private MemoryStream _PNGStream = null;
136 
137  /// <summary>
138  /// Contains a representation of the image in PNG format. Generated at the first access and cached until the image is disposed.
139  /// </summary>
140  public MemoryStream PNGStream
141  {
142  get
143  {
144  if (_PNGStream == null)
145  {
146  _PNGStream = new MemoryStream();
147  this.EncodeAsPNG(_PNGStream);
148  }
149  _PNGStream.Seek(0, SeekOrigin.Begin);
150  return _PNGStream;
151  }
152  }
153 
154  /// <summary>
155  /// Default constructor, necessary for inheritance.
156  /// </summary>
157  protected RasterImage()
158  {
159 
160  }
161 
162  /// <summary>
163  /// Creates a new <see cref="RasterImage"/> instance from the specified pixel data in RGB or RGBA format.
164  /// </summary>
165  /// <param name="pixelData">The address of the image pixel data in RGB or RGBA format.</param>
166  /// <param name="width">The width in pixels of the image.</param>
167  /// <param name="height">The height in pixels of the image.</param>
168  /// <param name="hasAlpha">true if the image is in RGBA format, false if it is in RGB format.</param>
169  /// <param name="interpolate">Whether the image should be interpolated when it is resized.</param>
170  public RasterImage(IntPtr pixelData, int width, int height, bool hasAlpha, bool interpolate)
171  {
172  this.Id = Guid.NewGuid().ToString();
173  this.ImageDataAddress = pixelData;
174  this.Width = width;
175  this.Height = height;
176  this.HasAlpha = hasAlpha;
177  this.Interpolate = interpolate;
178  }
179 
180  /// <summary>
181  /// Creates a new <see cref="RasterImage"/> instance from the specified pixel data in RGB or RGBA format.
182  /// </summary>
183  /// <param name="pixelData">The address of the image pixel data in RGB or RGBA format wrapped in a <see cref="DisposableIntPtr"/>. The <see cref="RasterImage"/> will take ownership of this memory.</param>
184  /// <param name="width">The width in pixels of the image.</param>
185  /// <param name="height">The height in pixels of the image.</param>
186  /// <param name="hasAlpha">true if the image is in RGBA format, false if it is in RGB format.</param>
187  /// <param name="interpolate">Whether the image should be interpolated when it is resized.</param>
188  public RasterImage(ref DisposableIntPtr pixelData, int width, int height, bool hasAlpha, bool interpolate)
189  {
190  this.Id = Guid.NewGuid().ToString();
191  this.ImageDataAddress = pixelData.InternalPointer;
192  this.DataHolder = pixelData;
193  this.Width = width;
194  this.Height = height;
195  this.HasAlpha = hasAlpha;
196  this.Interpolate = interpolate;
197  }
198 
199  /// <summary>
200  /// Creates a new <see cref="RasterImage"/> instance copying the specified pixel data.
201  /// </summary>
202  /// <param name="data">The image pixel data that will be copied.</param>
203  /// <param name="width">The width in pixels of the image.</param>
204  /// <param name="height">The height in pixels of the image.</param>
205  /// <param name="pixelFormat">The format of the pixel data.</param>
206  /// <param name="interpolate">Whether the image should be interpolated when it is resized.</param>
207  public RasterImage(byte[] data, int width, int height, PixelFormats pixelFormat, bool interpolate)
208  {
209  this.ImageDataAddress = Marshal.AllocHGlobal(data.Length);
210  GC.AddMemoryPressure(data.Length);
212  this.Id = Guid.NewGuid().ToString();
213  this.Width = width;
214  this.Height = height;
215  this.Interpolate = interpolate;
216 
217  switch (pixelFormat)
218  {
219  case PixelFormats.RGB:
220  case PixelFormats.RGBA:
221  Marshal.Copy(data, 0, this.ImageDataAddress, data.Length);
222  this.HasAlpha = pixelFormat == PixelFormats.RGBA;
223  break;
224 
225  case PixelFormats.BGRA:
226  case PixelFormats.BGR:
227  this.HasAlpha = pixelFormat == PixelFormats.BGRA;
228 
229  int pixelSize = pixelFormat == PixelFormats.BGRA ? 4 : 3;
230  int pixelCount = width * height;
231 
232  unsafe
233  {
234  byte* dataPointer = (byte*)this.ImageDataAddress;
235  for (int i = 0; i < pixelCount; i++)
236  {
237  dataPointer[i * pixelSize] = data[i * pixelSize + 2];
238  dataPointer[i * pixelSize + 1] = data[i * pixelSize + 1];
239  dataPointer[i * pixelSize + 2] = data[i * pixelSize];
240  if (pixelSize == 4)
241  {
242  dataPointer[i * pixelSize + 3] = data[i * pixelSize + 3];
243  }
244  }
245  }
246  break;
247  }
248  }
249 
250  private void EncodeAsPNG(Stream outputStream)
251  {
252  unsafe
253  {
254  PNGEncoder.SavePNG((byte*)this.ImageDataAddress, this.Width, this.Height, this.HasAlpha, outputStream, PNGEncoder.FilterModes.Adaptive);
255  }
256  }
257 
258  /// <summary>
259  /// Disposes the <see cref="PNGStream"/>. Also useful if is is necessary to regenerate it, e.g. because the underlying image pixel data has changed.
260  /// </summary>
261  public void ClearPNGCache()
262  {
263  _PNGStream?.Dispose();
264  _PNGStream = null;
265  }
266 
267  private bool disposedValue;
268 
269  /// <inheritdoc/>
270  protected virtual void Dispose(bool disposing)
271  {
272  if (!disposedValue)
273  {
274  if (disposing)
275  {
276  _PNGStream?.Dispose();
277 
278  if (DataHolder != null)
279  {
280  DataHolder.Dispose();
281  GC.RemoveMemoryPressure(Height * Width * (HasAlpha ? 4 : 3));
282  }
283  }
284  disposedValue = true;
285  }
286  }
287 
288  ///<inheritdoc/>
289  ~RasterImage()
290  {
291  Dispose(disposing: false);
292  }
293 
294  /// <inheritdoc/>
295  public void Dispose()
296  {
297  Dispose(disposing: true);
298  GC.SuppressFinalize(this);
299  }
300  }
301 }
VectSharp.RasterImage.PNGStream
MemoryStream PNGStream
Contains a representation of the image in PNG format. Generated at the first access and cached until ...
Definition: RasterImage.cs:141
VectSharp.PixelFormats.RGB
@ RGB
RGB 24bpp format.
VectSharp.RasterImage
Represents a raster image, created from raw pixel data. Consider using the derived classes included i...
Definition: RasterImage.cs:99
VectSharp.DisposableIntPtr
An IDisposable wrapper around an IntPtr that frees the allocated memory when it is disposed.
Definition: RasterImage.cs:54
VectSharp.PixelFormats.RGBA
@ RGBA
RGBA 32bpp format.
VectSharp
Definition: Brush.cs:26
VectSharp.RasterImage.Width
int Width
The width in pixels of the image.
Definition: RasterImage.cs:123
VectSharp.RasterImage.Interpolate
bool Interpolate
Determines whether the image should be interpolated when it is resized.
Definition: RasterImage.cs:133
VectSharp.RasterImage.HasAlpha
bool HasAlpha
Determines whether the image has an alpha channel.
Definition: RasterImage.cs:118
VectSharp.DisposableIntPtr.DisposableIntPtr
DisposableIntPtr(IntPtr pointer)
Create a new DisposableIntPtr.
Definition: RasterImage.cs:64
VectSharp.PixelFormats.BGR
@ BGR
BGR 24bpp format.
VectSharp.DisposableIntPtr.InternalPointer
readonly IntPtr InternalPointer
The pointer to the unmanaged memory.
Definition: RasterImage.cs:58
VectSharp.RasterImage.Dispose
void Dispose()
Definition: RasterImage.cs:295
VectSharp.RasterImage.RasterImage
RasterImage(IntPtr pixelData, int width, int height, bool hasAlpha, bool interpolate)
Creates a new RasterImage instance from the specified pixel data in RGB or RGBA format.
Definition: RasterImage.cs:170
VectSharp.RasterImage.DataHolder
IDisposable DataHolder
An IDisposable that will be disposed when the image is disposed.
Definition: RasterImage.cs:108
VectSharp.RasterImage.Height
int Height
The height in pixels of the image.
Definition: RasterImage.cs:128
VectSharp.PixelFormats
PixelFormats
Represents the pixel format of a raster image.
Definition: RasterImage.cs:28
VectSharp.PixelFormats.BGRA
@ BGRA
BGR 32bpp format.
VectSharp.RasterImage.ImageDataAddress
IntPtr ImageDataAddress
The memory address of the image pixel data.
Definition: RasterImage.cs:103
VectSharp.RasterImage.ClearPNGCache
void ClearPNGCache()
Disposes the PNGStream. Also useful if is is necessary to regenerate it, e.g. because the underlying ...
Definition: RasterImage.cs:261
VectSharp.RasterImage.RasterImage
RasterImage(ref DisposableIntPtr pixelData, int width, int height, bool hasAlpha, bool interpolate)
Creates a new RasterImage instance from the specified pixel data in RGB or RGBA format.
Definition: RasterImage.cs:188
VectSharp.RasterImage.RasterImage
RasterImage(byte[] data, int width, int height, PixelFormats pixelFormat, bool interpolate)
Creates a new RasterImage instance copying the specified pixel data.
Definition: RasterImage.cs:207
VectSharp.RasterImage.Id
string Id
A univocal identifier for this image.
Definition: RasterImage.cs:113