Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
FreeImageWrapper.cs
Go to the documentation of this file.
1 // ==========================================================
2 // FreeImage 3 .NET wrapper
3 // Original FreeImage 3 functions and .NET compatible derived functions
4 //
5 // Design and implementation by
6 // - Jean-Philippe Goerke (jpgoerke@users.sourceforge.net)
7 // - Carsten Klein (cklein05@users.sourceforge.net)
8 //
9 // Contributors:
10 // - David Boland (davidboland@vodafone.ie)
11 //
12 // Main reference : MSDN Knowlede Base
13 //
14 // This file is part of FreeImage 3
15 //
16 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
17 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
18 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
19 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
20 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
21 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
22 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
23 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
24 // THIS DISCLAIMER.
25 //
26 // Use at your own risk!
27 // ==========================================================
28 
29 // ==========================================================
30 // CVS
31 // $Revision: 1.19 $
32 // $Date: 2011/10/02 13:00:45 $
33 // $Id: FreeImageWrapper.cs,v 1.19 2011/10/02 13:00:45 drolon Exp $
34 // ==========================================================
35 
36 using System;
37 using System.Collections;
38 using System.Collections.Generic;
39 using System.Drawing;
40 using System.Drawing.Imaging;
41 using System.IO;
42 using System.Reflection;
43 using System.Runtime.InteropServices;
44 using FreeImageAPI.IO;
45 using FreeImageAPI.Metadata;
46 
47 namespace FreeImageAPI
48 {
49  /// <summary>
50  /// Static class importing functions from the FreeImage library
51  /// and providing additional functions.
52  /// </summary>
53  public static partial class FreeImage
54  {
55  #region Constants
56 
57  /// <summary>
58  /// Array containing all 'FREE_IMAGE_MDMODEL's.
59  /// </summary>
60  public static readonly FREE_IMAGE_MDMODEL[] FREE_IMAGE_MDMODELS =
61  (FREE_IMAGE_MDMODEL[])Enum.GetValues(typeof(FREE_IMAGE_MDMODEL));
62 
63  /// <summary>
64  /// Stores handles used to read from streams.
65  /// </summary>
66  private static Dictionary<FIMULTIBITMAP, fi_handle> streamHandles =
67  new Dictionary<FIMULTIBITMAP, fi_handle>();
68 
69  /// <summary>
70  /// Version of the wrapper library.
71  /// </summary>
72  private static Version WrapperVersion;
73 
74  private const int DIB_RGB_COLORS = 0;
75  private const int DIB_PAL_COLORS = 1;
76  private const int CBM_INIT = 0x4;
77 
78  /// <summary>
79  /// An uncompressed format.
80  /// </summary>
81  public const int BI_RGB = 0;
82 
83  /// <summary>
84  /// A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format is a 2-byte
85  /// format consisting of a count byte followed by a byte containing a color index.
86  /// </summary>
87  public const int BI_RLE8 = 1;
88 
89  /// <summary>
90  /// An RLE format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting
91  /// of a count byte followed by two word-length color indexes.
92  /// </summary>
93  public const int BI_RLE4 = 2;
94 
95  /// <summary>
96  /// Specifies that the bitmap is not compressed and that the color table consists of three
97  /// <b>DWORD</b> color masks that specify the red, green, and blue components, respectively,
98  /// of each pixel. This is valid when used with 16- and 32-bpp bitmaps.
99  /// </summary>
100  public const int BI_BITFIELDS = 3;
101 
102  /// <summary>
103  /// <b>Windows 98/Me, Windows 2000/XP:</b> Indicates that the image is a JPEG image.
104  /// </summary>
105  public const int BI_JPEG = 4;
106 
107  /// <summary>
108  /// <b>Windows 98/Me, Windows 2000/XP:</b> Indicates that the image is a PNG image.
109  /// </summary>
110  public const int BI_PNG = 5;
111 
112  #endregion
113 
114  #region General functions
115 
116  /// <summary>
117  /// Returns the internal version of this FreeImage .NET wrapper.
118  /// </summary>
119  /// <returns>The internal version of this FreeImage .NET wrapper.</returns>
120  public static Version GetWrapperVersion()
121  {
122  if (WrapperVersion == null)
123  {
124  try
125  {
126  object[] attributes = Assembly.GetAssembly(typeof(FreeImage))
127  .GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
128  if ((attributes != null) && (attributes.Length != 0))
129  {
130  AssemblyFileVersionAttribute attribute =
131  attributes[0] as AssemblyFileVersionAttribute;
132  if ((attribute != null) && (attribute.Version != null))
133  {
134  return (WrapperVersion = new Version(attribute.Version));
135  }
136  }
137  }
138  catch
139  {
140 
141  }
142 
143  WrapperVersion = new Version();
144  }
145 
146  return WrapperVersion;
147  }
148 
149  /// <summary>
150  /// Returns the version of the native FreeImage library.
151  /// </summary>
152  /// <returns>The version of the native FreeImage library.</returns>
153  public static Version GetNativeVersion()
154  {
155  return new Version(GetVersion());
156  }
157 
158  /// <summary>
159  /// Returns a value indicating if the FreeImage library is available or not.
160  /// See remarks for further details.
161  /// </summary>
162  /// <returns><c>false</c> if the file is not available or out of date;
163  /// <c>true</c>, otherwise.</returns>
164  /// <remarks>
165  /// The FreeImage.NET library is a wrapper for the native C++ library
166  /// (FreeImage.dll ... dont mix ist up with this library FreeImageNet.dll).
167  /// The native library <b>must</b> be either in the same folder as the program's
168  /// executable or in a folder contained in the envirent variable <i>PATH</i>
169  /// (for example %WINDIR%\System32).<para/>
170  /// Further more must both libraries, including the program itself,
171  /// be the same architecture (x86 or x64).
172  /// </remarks>
173  public static bool IsAvailable()
174  {
175  try
176  {
177  // Call a static fast executing function
178  Version nativeVersion = new Version(GetVersion());
179  Version wrapperVersion = GetWrapperVersion();
180  // No exception thrown, the library seems to be present
181  return
182  (nativeVersion.Major > wrapperVersion.Major) ||
183  ((nativeVersion.Major == wrapperVersion.Major) && (nativeVersion.Minor > wrapperVersion.Minor)) ||
184  ((nativeVersion.Major == wrapperVersion.Major) && (nativeVersion.Minor == wrapperVersion.Minor) && (nativeVersion.Build >= wrapperVersion.Build));
185  }
186  catch (DllNotFoundException)
187  {
188  return false;
189  }
190  catch (EntryPointNotFoundException)
191  {
192  return false;
193  }
194  catch (BadImageFormatException)
195  {
196  return false;
197  }
198  }
199 
200  #endregion
201 
202  #region Bitmap management functions
203 
204  /// <summary>
205  /// Creates a new bitmap in memory.
206  /// </summary>
207  /// <param name="width">Width of the new bitmap.</param>
208  /// <param name="height">Height of the new bitmap.</param>
209  /// <param name="bpp">Bit depth of the new Bitmap.
210  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
211  /// <returns>Handle to a FreeImage bitmap.</returns>
212  public static FIBITMAP Allocate(int width, int height, int bpp)
213  {
214  return Allocate(width, height, bpp, 0, 0, 0);
215  }
216 
217  /// <summary>
218  /// Creates a new bitmap in memory.
219  /// </summary>
220  /// <param name="type">Type of the image.</param>
221  /// <param name="width">Width of the new bitmap.</param>
222  /// <param name="height">Height of the new bitmap.</param>
223  /// <param name="bpp">Bit depth of the new Bitmap.
224  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
225  /// <returns>Handle to a FreeImage bitmap.</returns>
226  public static FIBITMAP AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp)
227  {
228  return AllocateT(type, width, height, bpp, 0, 0, 0);
229  }
230 
231  /// <summary>
232  /// Allocates a new image of the specified width, height and bit depth and optionally
233  /// fills it with the specified color. See remarks for further details.
234  /// </summary>
235  /// <param name="width">Width of the new bitmap.</param>
236  /// <param name="height">Height of the new bitmap.</param>
237  /// <param name="bpp">Bit depth of the new bitmap.
238  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.</param>
239  /// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
240  /// <param name="options">Options to enable or disable function-features.</param>
241  /// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
242  /// <returns>Handle to a FreeImage bitmap.</returns>
243  /// <remarks>
244  /// This function is an extension to <see cref="Allocate"/>, which additionally supports
245  /// specifying a palette to be set for the newly create image, as well as specifying a
246  /// background color, the newly created image should initially be filled with.
247  /// <para/>
248  /// Basically, this function internally relies on function <see cref="Allocate"/>, followed by a
249  /// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
250  /// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
251  /// documented for function <see cref="FillBackground&lt;T&gt;"/>.
252  /// So, please refer to the documentation of <see cref="FillBackground&lt;T&gt;"/> to
253  /// learn more about parameters <paramref name="color"/> and <paramref name="options"/>.
254  /// <para/>
255  /// The palette specified through parameter <paramref name="palette"/> is only copied to the
256  /// newly created image, if the desired bit depth is smaller than or equal to 8 bits per pixel.
257  /// In other words, the <paramref name="palette"/> parameter is only taken into account for
258  /// palletized images. So, for an 8-bit image, the length is 256, for an 4-bit image it is 16
259  /// and it is 2 for a 1-bit image. In other words, this function does not support partial palettes.
260  /// <para/>
261  /// However, specifying a palette is not necesarily needed, even for palletized images. This
262  /// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
263  /// If the specified background color is a greyscale value (red = green = blue) or if option
264  /// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
265  /// is created. For a 1-bit image, only if the specified background color is either black or white,
266  /// a monochrome palette, consisting of black and white only is created. In any case, the darker
267  /// colors are stored at the smaller palette indices.
268  /// <para/>
269  /// If the specified background color is not a greyscale value, or is neither black nor white
270  /// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
271  /// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
272  /// is implicit, so the specified <paramref name="color"/> is applied to the palette entry,
273  /// specified by the background color's <see cref="RGBQUAD.rgbReserved"/> field.
274  /// The image is then filled with this palette index.
275  /// <para/>
276  /// This function returns a newly created image as function <see cref="Allocate"/> does, if both
277  /// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
278  /// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
279  /// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
280  /// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
281  /// However, in the latter case, this function returns an image, whose
282  /// pixels are all initialized with zeros so, the image will be filled with the color of the
283  /// first palette entry.
284  /// </remarks>
285  public static FIBITMAP AllocateEx(int width, int height, int bpp,
286  RGBQUAD? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette)
287  {
288  return AllocateEx(width, height, bpp, color, options, palette, 0, 0, 0);
289  }
290 
291  /// <summary>
292  /// Allocates a new image of the specified width, height and bit depth and optionally
293  /// fills it with the specified color. See remarks for further details.
294  /// </summary>
295  /// <param name="width">Width of the new bitmap.</param>
296  /// <param name="height">Height of the new bitmap.</param>
297  /// <param name="bpp">Bit depth of the new bitmap.
298  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.</param>
299  /// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
300  /// <param name="options">Options to enable or disable function-features.</param>
301  /// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
302  /// <param name="red_mask">Red part of the color layout.
303  /// eg: 0xFF0000</param>
304  /// <param name="green_mask">Green part of the color layout.
305  /// eg: 0x00FF00</param>
306  /// <param name="blue_mask">Blue part of the color layout.
307  /// eg: 0x0000FF</param>
308  /// <returns>Handle to a FreeImage bitmap.</returns>
309  /// <remarks>
310  /// This function is an extension to <see cref="Allocate"/>, which additionally supports
311  /// specifying a palette to be set for the newly create image, as well as specifying a
312  /// background color, the newly created image should initially be filled with.
313  /// <para/>
314  /// Basically, this function internally relies on function <see cref="Allocate"/>, followed by a
315  /// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
316  /// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
317  /// documented for function <see cref="FillBackground&lt;T&gt;"/>.
318  /// So, please refer to the documentation of <see cref="FillBackground&lt;T&gt;"/> to
319  /// learn more about parameters <paramref name="color"/> and <paramref name="options"/>.
320  /// <para/>
321  /// The palette specified through parameter <paramref name="palette"/> is only copied to the
322  /// newly created image, if the desired bit depth is smaller than or equal to 8 bits per pixel.
323  /// In other words, the <paramref name="palette"/> parameter is only taken into account for
324  /// palletized images. So, for an 8-bit image, the length is 256, for an 4-bit image it is 16
325  /// and it is 2 for a 1-bit image. In other words, this function does not support partial palettes.
326  /// <para/>
327  /// However, specifying a palette is not necesarily needed, even for palletized images. This
328  /// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
329  /// If the specified background color is a greyscale value (red = green = blue) or if option
330  /// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
331  /// is created. For a 1-bit image, only if the specified background color is either black or white,
332  /// a monochrome palette, consisting of black and white only is created. In any case, the darker
333  /// colors are stored at the smaller palette indices.
334  /// <para/>
335  /// If the specified background color is not a greyscale value, or is neither black nor white
336  /// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
337  /// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
338  /// is implicit, so the specified <paramref name="color"/> is applied to the palette entry,
339  /// specified by the background color's <see cref="RGBQUAD.rgbReserved"/> field.
340  /// The image is then filled with this palette index.
341  /// <para/>
342  /// This function returns a newly created image as function <see cref="Allocate"/> does, if both
343  /// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
344  /// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
345  /// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
346  /// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
347  /// However, in the latter case, this function returns an image, whose
348  /// pixels are all initialized with zeros so, the image will be filled with the color of the
349  /// first palette entry.
350  /// </remarks>
351  public static FIBITMAP AllocateEx(int width, int height, int bpp,
352  RGBQUAD? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette,
353  uint red_mask, uint green_mask, uint blue_mask)
354  {
355  if ((palette != null) && (bpp <= 8) && (palette.Length < (1 << bpp)))
356  return FIBITMAP.Zero;
357 
358  if (color.HasValue)
359  {
360  GCHandle handle = new GCHandle();
361  try
362  {
363  RGBQUAD[] buffer = new RGBQUAD[] { color.Value };
364  handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
365  return AllocateEx(width, height, bpp, handle.AddrOfPinnedObject(),
366  options, palette, red_mask, green_mask, blue_mask);
367  }
368  finally
369  {
370  if (handle.IsAllocated)
371  handle.Free();
372  }
373  }
374  else
375  {
376  return AllocateEx(width, height, bpp, IntPtr.Zero,
377  options, palette, red_mask, green_mask, blue_mask);
378  }
379  }
380 
381  /// <summary>
382  /// Allocates a new image of the specified type, width, height and bit depth and optionally
383  /// fills it with the specified color. See remarks for further details.
384  /// </summary>
385  /// <typeparam name="T">The type of the specified color.</typeparam>
386  /// <param name="type">Type of the image.</param>
387  /// <param name="width">Width of the new bitmap.</param>
388  /// <param name="height">Height of the new bitmap.</param>
389  /// <param name="bpp">Bit depth of the new bitmap.
390  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
391  /// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
392  /// <param name="options">Options to enable or disable function-features.</param>
393  /// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
394  /// <returns>Handle to a FreeImage bitmap.</returns>
395  /// <remarks>
396  /// This function is an extension to <see cref="AllocateT"/>, which additionally supports
397  /// specifying a palette to be set for the newly create image, as well as specifying a
398  /// background color, the newly created image should initially be filled with.
399  /// <para/>
400  /// Basically, this function internally relies on function <see cref="AllocateT"/>, followed by a
401  /// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
402  /// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
403  /// documented for function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the
404  /// documentation of <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters color and options.
405  /// <para/>
406  /// The palette specified through parameter palette is only copied to the newly created
407  /// image, if its image type is <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> and the desired bit
408  /// depth is smaller than or equal to 8 bits per pixel. In other words, the <paramref name="palette"/>
409  /// palette is only taken into account for palletized images. However, if the preceding conditions
410  /// match and if <paramref name="palette"/> is not <c>null</c>, the palette is assumed to be at
411  /// least as large as the size of a fully populated palette for the desired bit depth.
412  /// So, for an 8-bit image, this length is 256, for an 4-bit image it is 16 and it is
413  /// 2 for a 1-bit image. In other words, this function does not support partial palettes.
414  /// <para/>
415  /// However, specifying a palette is not necesarily needed, even for palletized images. This
416  /// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
417  /// If the specified background color is a greyscale value (red = green = blue) or if option
418  /// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
419  /// is created. For a 1-bit image, only if the specified background color is either black or white,
420  /// a monochrome palette, consisting of black and white only is created. In any case, the darker
421  /// colors are stored at the smaller palette indices.
422  /// <para/>
423  /// If the specified background color is not a greyscale value, or is neither black nor white
424  /// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
425  /// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
426  /// is implicit, so the specified color is applied to the palette entry, specified by the
427  /// background color's <see cref="RGBQUAD.rgbReserved"/> field. The image is then filled with
428  /// this palette index.
429  /// <para/>
430  /// This function returns a newly created image as function <see cref="AllocateT"/> does, if both
431  /// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
432  /// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
433  /// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
434  /// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
435  /// However, in the latter case, this function returns an image, whose
436  /// pixels are all initialized with zeros so, the image will be filled with the color of the
437  /// first palette entry.
438  /// </remarks>
439  public static FIBITMAP AllocateExT<T>(FREE_IMAGE_TYPE type, int width, int height, int bpp,
440  T? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette) where T : struct
441  {
442  return AllocateExT(type, width, height, bpp, color, options, palette, 0, 0, 0);
443  }
444 
445  /// <summary>
446  /// Allocates a new image of the specified type, width, height and bit depth and optionally
447  /// fills it with the specified color. See remarks for further details.
448  /// </summary>
449  /// <typeparam name="T">The type of the specified color.</typeparam>
450  /// <param name="type">Type of the image.</param>
451  /// <param name="width">Width of the new bitmap.</param>
452  /// <param name="height">Height of the new bitmap.</param>
453  /// <param name="bpp">Bit depth of the new bitmap.
454  /// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
455  /// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
456  /// <param name="options">Options to enable or disable function-features.</param>
457  /// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
458  /// <param name="red_mask">Red part of the color layout.
459  /// eg: 0xFF0000</param>
460  /// <param name="green_mask">Green part of the color layout.
461  /// eg: 0x00FF00</param>
462  /// <param name="blue_mask">Blue part of the color layout.
463  /// eg: 0x0000FF</param>
464  /// <returns>Handle to a FreeImage bitmap.</returns>
465  /// <remarks>
466  /// This function is an extension to <see cref="AllocateT"/>, which additionally supports
467  /// specifying a palette to be set for the newly create image, as well as specifying a
468  /// background color, the newly created image should initially be filled with.
469  /// <para/>
470  /// Basically, this function internally relies on function <see cref="AllocateT"/>, followed by a
471  /// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
472  /// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
473  /// documented for function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the
474  /// documentation of <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters color and options.
475  /// <para/>
476  /// The palette specified through parameter palette is only copied to the newly created
477  /// image, if its image type is <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> and the desired bit
478  /// depth is smaller than or equal to 8 bits per pixel. In other words, the <paramref name="palette"/>
479  /// palette is only taken into account for palletized images. However, if the preceding conditions
480  /// match and if <paramref name="palette"/> is not <c>null</c>, the palette is assumed to be at
481  /// least as large as the size of a fully populated palette for the desired bit depth.
482  /// So, for an 8-bit image, this length is 256, for an 4-bit image it is 16 and it is
483  /// 2 for a 1-bit image. In other words, this function does not support partial palettes.
484  /// <para/>
485  /// However, specifying a palette is not necesarily needed, even for palletized images. This
486  /// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
487  /// If the specified background color is a greyscale value (red = green = blue) or if option
488  /// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
489  /// is created. For a 1-bit image, only if the specified background color is either black or white,
490  /// a monochrome palette, consisting of black and white only is created. In any case, the darker
491  /// colors are stored at the smaller palette indices.
492  /// <para/>
493  /// If the specified background color is not a greyscale value, or is neither black nor white
494  /// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
495  /// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
496  /// is implicit, so the specified color is applied to the palette entry, specified by the
497  /// background color's <see cref="RGBQUAD.rgbReserved"/> field. The image is then filled with
498  /// this palette index.
499  /// <para/>
500  /// This function returns a newly created image as function <see cref="AllocateT"/> does, if both
501  /// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
502  /// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
503  /// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
504  /// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
505  /// However, in the latter case, this function returns an image, whose
506  /// pixels are all initialized with zeros so, the image will be filled with the color of the
507  /// first palette entry.
508  /// </remarks>
509  public static FIBITMAP AllocateExT<T>(FREE_IMAGE_TYPE type, int width, int height, int bpp,
510  T? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette,
511  uint red_mask, uint green_mask, uint blue_mask) where T : struct
512  {
513  if ((palette != null) && (bpp <= 8) && (palette.Length < (1 << bpp)))
514  return FIBITMAP.Zero;
515 
516  if (color.HasValue)
517  {
518  if (!CheckColorType(type, color.Value))
519  return FIBITMAP.Zero;
520 
521  GCHandle handle = new GCHandle();
522  try
523  {
524  T[] buffer = new T[] { color.Value };
525  handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
526  return AllocateExT(type, width, height, bpp, handle.AddrOfPinnedObject(),
527  options, palette, red_mask, green_mask, blue_mask);
528  }
529  finally
530  {
531  if (handle.IsAllocated)
532  handle.Free();
533  }
534  }
535  else
536  {
537  return AllocateExT(type, width, height, bpp, IntPtr.Zero,
538  options, palette, red_mask, green_mask, blue_mask);
539  }
540  }
541 
542  /// <summary>
543  /// Converts a FreeImage bitmap to a .NET <see cref="System.Drawing.Bitmap"/>.
544  /// </summary>
545  /// <param name="dib">Handle to a FreeImage bitmap.</param>
546  /// <returns>The converted .NET <see cref="System.Drawing.Bitmap"/>.</returns>
547  /// <remarks>Copying metadata has been disabled until a proper way
548  /// of reading and storing metadata in a .NET bitmap is found.</remarks>
549  /// <exception cref="ArgumentNullException">
550  /// <paramref name="dib"/> is null.</exception>
551  /// <exception cref="ArgumentException">
552  /// The image type of <paramref name="dib"/> is not FIT_BITMAP.</exception>
553  public static Bitmap GetBitmap(FIBITMAP dib)
554  {
555  return GetBitmap(dib, true);
556  }
557 
558  /// <summary>
559  /// Converts a FreeImage bitmap to a .NET <see cref="System.Drawing.Bitmap"/>.
560  /// </summary>
561  /// <param name="dib">Handle to a FreeImage bitmap.</param>
562  /// <param name="copyMetadata">When true existing metadata will be copied.</param>
563  /// <returns>The converted .NET <see cref="System.Drawing.Bitmap"/>.</returns>
564  /// <remarks>Copying metadata has been disabled until a proper way
565  /// of reading and storing metadata in a .NET bitmap is found.</remarks>
566  /// <exception cref="ArgumentNullException">
567  /// <paramref name="dib"/> is null.</exception>
568  /// <exception cref="ArgumentException">
569  /// The image type of <paramref name="dib"/> is not FIT_BITMAP.</exception>
570  internal static Bitmap GetBitmap(FIBITMAP dib, bool copyMetadata)
571  {
572  if (dib.IsNull)
573  {
574  throw new ArgumentNullException("dib");
575  }
576  if (GetImageType(dib) != FREE_IMAGE_TYPE.FIT_BITMAP)
577  {
578  throw new ArgumentException("Only bitmaps with type of FIT_BITMAP can be converted.");
579  }
580 
581  PixelFormat format = GetPixelFormat(dib);
582 
583  if ((format == PixelFormat.Undefined) && (GetBPP(dib) == 16u))
584  {
585  throw new ArgumentException("Only 16bit 555 and 565 are supported.");
586  }
587 
588  int height = (int)GetHeight(dib);
589  int width = (int)GetWidth(dib);
590  int pitch = (int)GetPitch(dib);
591 
592  Bitmap result = new Bitmap(width, height, format);
593  BitmapData data;
594  // Locking the complete bitmap in writeonly mode
595  data = result.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, format);
596  // Writing the bitmap data directly into the new created .NET bitmap.
597  ConvertToRawBits(data.Scan0, dib, pitch, GetBPP(dib),
598  GetRedMask(dib), GetGreenMask(dib), GetBlueMask(dib), true);
599  // Unlock the bitmap
600  result.UnlockBits(data);
601  // Apply the bitmap resolution
602  if((GetResolutionX(dib) > 0) && (GetResolutionY(dib) > 0))
603  {
604  // SetResolution will throw an exception when zero values are given on input
605  result.SetResolution(GetResolutionX(dib), GetResolutionY(dib));
606  }
607  // Check whether the bitmap has a palette
608  if (GetPalette(dib) != IntPtr.Zero)
609  {
610  // Get the bitmaps palette to apply changes
611  ColorPalette palette = result.Palette;
612  // Get the orgininal palette
613  Color[] colorPalette = new Palette(dib).ColorData;
614  // Get the maximum number of palette entries to copy
615  int entriesToCopy = Math.Min(colorPalette.Length, palette.Entries.Length);
616 
617  // Check whether the bitmap is transparent
618  if (IsTransparent(dib))
619  {
620  byte[] transTable = GetTransparencyTableEx(dib);
621  int i = 0;
622  int maxEntriesWithTrans = Math.Min(entriesToCopy, transTable.Length);
623  // Copy palette entries and include transparency
624  for (; i < maxEntriesWithTrans; i++)
625  {
626  palette.Entries[i] = Color.FromArgb(transTable[i], colorPalette[i]);
627  }
628  // Copy palette entries and that have no transparancy
629  for (; i < entriesToCopy; i++)
630  {
631  palette.Entries[i] = Color.FromArgb(0xFF, colorPalette[i]);
632  }
633  }
634  else
635  {
636  for (int i = 0; i < entriesToCopy; i++)
637  {
638  palette.Entries[i] = colorPalette[i];
639  }
640  }
641 
642  // Set the bitmaps palette
643  result.Palette = palette;
644  }
645  // Copy metadata
646  if (copyMetadata)
647  {
648  try
649  {
650  List<PropertyItem> list = new List<PropertyItem>();
651  // Get a list of all types
652  FITAG tag;
653  FIMETADATA mData;
654  foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
655  {
656  // Get a unique search handle
657  mData = FindFirstMetadata(model, dib, out tag);
658  // Check if metadata exists for this type
659  if (mData.IsNull) continue;
660  do
661  {
662  PropertyItem propItem = CreatePropertyItem();
663  propItem.Len = (int)GetTagLength(tag);
664  propItem.Id = (int)GetTagID(tag);
665  propItem.Type = (short)GetTagType(tag);
666  byte[] buffer = new byte[propItem.Len];
667 
668  unsafe
669  {
670  byte* src = (byte*)GetTagValue(tag);
671  fixed (byte* dst = buffer)
672  {
673  CopyMemory(dst, src, (uint)propItem.Len);
674  }
675  }
676 
677  propItem.Value = buffer;
678  list.Add(propItem);
679  }
680  while (FindNextMetadata(mData, out tag));
681  FindCloseMetadata(mData);
682  }
683  foreach (PropertyItem propItem in list)
684  {
685  result.SetPropertyItem(propItem);
686  }
687  }
688  catch
689  {
690  }
691  }
692  return result;
693  }
694 
695  /// <summary>
696  /// Converts an .NET <see cref="System.Drawing.Bitmap"/> into a FreeImage bitmap.
697  /// </summary>
698  /// <param name="bitmap">The <see cref="System.Drawing.Bitmap"/> to convert.</param>
699  /// <returns>Handle to a FreeImage bitmap.</returns>
700  /// <remarks>Copying metadata has been disabled until a proper way
701  /// of reading and storing metadata in a .NET bitmap is found.</remarks>
702  /// <exception cref="ArgumentNullException">
703  /// <paramref name="bitmap"/> is null.</exception>
704  /// <exception cref="ArgumentException">
705  /// The bitmaps pixelformat is invalid.</exception>
706  public static FIBITMAP CreateFromBitmap(Bitmap bitmap)
707  {
708  return CreateFromBitmap(bitmap, false);
709  }
710 
711  /// <summary>
712  /// Converts an .NET <see cref="System.Drawing.Bitmap"/> into a FreeImage bitmap.
713  /// </summary>
714  /// <param name="bitmap">The <see cref="System.Drawing.Bitmap"/> to convert.</param>
715  /// <param name="copyMetadata">When true existing metadata will be copied.</param>
716  /// <returns>Handle to a FreeImage bitmap.</returns>
717  /// <remarks>Copying metadata has been disabled until a proper way
718  /// of reading and storing metadata in a .NET bitmap is found.</remarks>
719  /// <exception cref="ArgumentNullException">
720  /// <paramref name="bitmap"/> is null.</exception>
721  /// <exception cref="ArgumentException">
722  /// The bitmaps pixelformat is invalid.</exception>
723  internal static FIBITMAP CreateFromBitmap(Bitmap bitmap, bool copyMetadata)
724  {
725  if (bitmap == null)
726  {
727  throw new ArgumentNullException("bitmap");
728  }
729  uint bpp, red_mask, green_mask, blue_mask;
730  FREE_IMAGE_TYPE type;
731  if (!GetFormatParameters(bitmap.PixelFormat, out type, out bpp, out red_mask, out green_mask, out blue_mask))
732  {
733  throw new ArgumentException("The bitmaps pixelformat is invalid.");
734  }
735 
736  // Locking the complete bitmap in readonly mode
737  BitmapData data = bitmap.LockBits(
738  new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
739  // Copying the bitmap data directly from the .NET bitmap
740  FIBITMAP result = ConvertFromRawBits(
741  data.Scan0,
742  type,
743  data.Width,
744  data.Height,
745  data.Stride,
746  bpp,
747  red_mask,
748  green_mask,
749  blue_mask,
750  true);
751  bitmap.UnlockBits(data);
752  // Handle palette
753  if (GetPalette(result) != IntPtr.Zero)
754  {
755  Palette palette = new Palette(result);
756  Color[] colors = bitmap.Palette.Entries;
757  // Only copy available palette entries
758  int entriesToCopy = Math.Min(palette.Length, colors.Length);
759  byte[] transTable = new byte[entriesToCopy];
760  for (int i = 0; i < entriesToCopy; i++)
761  {
762  RGBQUAD color = (RGBQUAD)colors[i];
763  color.rgbReserved = 0x00;
764  palette[i] = color;
765  transTable[i] = colors[i].A;
766  }
767  if ((bitmap.Flags & (int)ImageFlags.HasAlpha) != 0)
768  {
769  FreeImage.SetTransparencyTable(result, transTable);
770  }
771  }
772  // Handle meta data
773  // Disabled
774  //if (copyMetadata)
775  //{
776  // foreach (PropertyItem propItem in bitmap.PropertyItems)
777  // {
778  // FITAG tag = CreateTag();
779  // SetTagLength(tag, (uint)propItem.Len);
780  // SetTagID(tag, (ushort)propItem.Id);
781  // SetTagType(tag, (FREE_IMAGE_MDTYPE)propItem.Type);
782  // SetTagValue(tag, propItem.Value);
783  // SetMetadata(FREE_IMAGE_MDMODEL.FIMD_EXIF_EXIF, result, "", tag);
784  // }
785  //}
786  return result;
787  }
788 
789  /// <summary>
790  /// Converts a raw bitmap to a FreeImage bitmap.
791  /// </summary>
792  /// <param name="bits">Array of bytes containing the raw bitmap.</param>
793  /// <param name="type">The type of the raw bitmap.</param>
794  /// <param name="width">The width in pixels of the raw bitmap.</param>
795  /// <param name="height">The height in pixels of the raw bitmap.</param>
796  /// <param name="pitch">Defines the total width of a scanline in the raw bitmap,
797  /// including padding bytes.</param>
798  /// <param name="bpp">The bit depth (bits per pixel) of the raw bitmap.</param>
799  /// <param name="red_mask">The bit mask describing the bits used to store a single
800  /// pixel's red component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
801  /// <param name="green_mask">The bit mask describing the bits used to store a single
802  /// pixel's green component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
803  /// <param name="blue_mask">The bit mask describing the bits used to store a single
804  /// pixel's blue component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
805  /// <param name="topdown">If true, the raw bitmap is stored in top-down order (top-left pixel first)
806  /// and in bottom-up order (bottom-left pixel first) otherwise.</param>
807  /// <returns>Handle to a FreeImage bitmap.</returns>
808  public static unsafe FIBITMAP ConvertFromRawBits(
809  byte[] bits,
810  FREE_IMAGE_TYPE type,
811  int width,
812  int height,
813  int pitch,
814  uint bpp,
815  uint red_mask,
816  uint green_mask,
817  uint blue_mask,
818  bool topdown)
819  {
820  fixed (byte* ptr = bits)
821  {
822  return ConvertFromRawBits(
823  (IntPtr)ptr,
824  type,
825  width,
826  height,
827  pitch,
828  bpp,
829  red_mask,
830  green_mask,
831  blue_mask,
832  topdown);
833  }
834  }
835 
836  /// <summary>
837  /// Converts a raw bitmap to a FreeImage bitmap.
838  /// </summary>
839  /// <param name="bits">Pointer to the memory block containing the raw bitmap.</param>
840  /// <param name="type">The type of the raw bitmap.</param>
841  /// <param name="width">The width in pixels of the raw bitmap.</param>
842  /// <param name="height">The height in pixels of the raw bitmap.</param>
843  /// <param name="pitch">Defines the total width of a scanline in the raw bitmap,
844  /// including padding bytes.</param>
845  /// <param name="bpp">The bit depth (bits per pixel) of the raw bitmap.</param>
846  /// <param name="red_mask">The bit mask describing the bits used to store a single
847  /// pixel's red component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
848  /// <param name="green_mask">The bit mask describing the bits used to store a single
849  /// pixel's green component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
850  /// <param name="blue_mask">The bit mask describing the bits used to store a single
851  /// pixel's blue component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
852  /// <param name="topdown">If true, the raw bitmap is stored in top-down order (top-left pixel first)
853  /// and in bottom-up order (bottom-left pixel first) otherwise.</param>
854  /// <returns>Handle to a FreeImage bitmap.</returns>
855  public static unsafe FIBITMAP ConvertFromRawBits(
856  IntPtr bits,
857  FREE_IMAGE_TYPE type,
858  int width,
859  int height,
860  int pitch,
861  uint bpp,
862  uint red_mask,
863  uint green_mask,
864  uint blue_mask,
865  bool topdown)
866  {
867  byte* addr = (byte*)bits;
868  if ((addr == null) || (width <= 0) || (height <= 0))
869  {
870  return FIBITMAP.Zero;
871  }
872 
873  FIBITMAP dib = AllocateT(type, width, height, (int)bpp, red_mask, green_mask, blue_mask);
874  if (dib != FIBITMAP.Zero)
875  {
876  if (topdown)
877  {
878  for (int i = height - 1; i >= 0; --i)
879  {
880  CopyMemory((byte*)GetScanLine(dib, i), addr, (int)GetLine(dib));
881  addr += pitch;
882  }
883  }
884  else
885  {
886  for (int i = 0; i < height; ++i)
887  {
888  CopyMemory((byte*)GetScanLine(dib, i), addr, (int)GetLine(dib));
889  addr += pitch;
890  }
891  }
892  }
893  return dib;
894  }
895 
896  /// <summary>
897  /// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
898  /// </summary>
899  /// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
900  /// <param name="filename">Name of the file to save to.</param>
901  /// <returns>Returns true on success, false on failure.</returns>
902  /// <exception cref="ArgumentNullException">
903  /// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
904  /// <exception cref="ArgumentException">
905  /// The bitmaps pixelformat is invalid.</exception>
906  public static bool SaveBitmap(Bitmap bitmap, string filename)
907  {
908  return SaveBitmap(
909  bitmap,
910  filename,
911  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
912  FREE_IMAGE_SAVE_FLAGS.DEFAULT);
913  }
914 
915  /// <summary>
916  /// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
917  /// </summary>
918  /// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
919  /// <param name="filename">Name of the file to save to.</param>
920  /// <param name="flags">Flags to enable or disable plugin-features.</param>
921  /// <returns>Returns true on success, false on failure.</returns>
922  /// <exception cref="ArgumentNullException">
923  /// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
924  /// <exception cref="ArgumentException">
925  /// The bitmaps pixelformat is invalid.</exception>
926  public static bool SaveBitmap(Bitmap bitmap, string filename, FREE_IMAGE_SAVE_FLAGS flags)
927  {
928  return SaveBitmap(
929  bitmap,
930  filename,
931  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
932  flags);
933  }
934 
935  /// <summary>
936  /// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
937  /// </summary>
938  /// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
939  /// <param name="filename">Name of the file to save to.</param>
940  /// <param name="format">Format of the bitmap. If the format should be taken from the
941  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
942  /// <param name="flags">Flags to enable or disable plugin-features.</param>
943  /// <returns>Returns true on success, false on failure.</returns>
944  /// <exception cref="ArgumentNullException">
945  /// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
946  /// <exception cref="ArgumentException">
947  /// The bitmaps pixelformat is invalid.</exception>
948  public static bool SaveBitmap(
949  Bitmap bitmap,
950  string filename,
951  FREE_IMAGE_FORMAT format,
953  {
954  FIBITMAP dib = CreateFromBitmap(bitmap);
955  bool result = SaveEx(dib, filename, format, flags);
956  Unload(dib);
957  return result;
958  }
959 
960  /// <summary>
961  /// Loads a FreeImage bitmap.
962  /// The file will be loaded with default loading flags.
963  /// </summary>
964  /// <param name="filename">The complete name of the file to load.</param>
965  /// <returns>Handle to a FreeImage bitmap.</returns>
966  /// <exception cref="FileNotFoundException">
967  /// <paramref name="filename"/> does not exists.</exception>
968  public static FIBITMAP LoadEx(string filename)
969  {
970  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
971  return LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
972  }
973 
974  /// <summary>
975  /// Loads a FreeImage bitmap.
976  /// Load flags can be provided by the flags parameter.
977  /// </summary>
978  /// <param name="filename">The complete name of the file to load.</param>
979  /// <param name="flags">Flags to enable or disable plugin-features.</param>
980  /// <returns>Handle to a FreeImage bitmap.</returns>
981  /// <exception cref="FileNotFoundException">
982  /// <paramref name="filename"/> does not exists.</exception>
983  public static FIBITMAP LoadEx(string filename, FREE_IMAGE_LOAD_FLAGS flags)
984  {
985  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
986  return LoadEx(filename, flags, ref format);
987  }
988 
989  /// <summary>
990  /// Loads a FreeImage bitmap.
991  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
992  /// real format is being analysed. If no plugin can read the file, format remains
993  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
994  /// The file will be loaded with default loading flags.
995  /// </summary>
996  /// <param name="filename">The complete name of the file to load.</param>
997  /// <param name="format">Format of the image. If the format is unknown use
998  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
999  /// In case a suitable format was found by LoadEx it will be returned in format.</param>
1000  /// <returns>Handle to a FreeImage bitmap.</returns>
1001  /// <exception cref="FileNotFoundException">
1002  /// <paramref name="filename"/> does not exists.</exception>
1003  public static FIBITMAP LoadEx(string filename, ref FREE_IMAGE_FORMAT format)
1004  {
1005  return LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
1006  }
1007 
1008  /// <summary>
1009  /// Loads a FreeImage bitmap.
1010  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
1011  /// real format is being analysed. If no plugin can read the file, format remains
1012  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
1013  /// Load flags can be provided by the flags parameter.
1014  /// </summary>
1015  /// <param name="filename">The complete name of the file to load.</param>
1016  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1017  /// <param name="format">Format of the image. If the format is unknown use
1018  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
1019  /// In case a suitable format was found by LoadEx it will be returned in format.
1020  /// </param>
1021  /// <returns>Handle to a FreeImage bitmap.</returns>
1022  /// <exception cref="FileNotFoundException">
1023  /// <paramref name="filename"/> does not exists.</exception>
1024  public static FIBITMAP LoadEx(string filename, FREE_IMAGE_LOAD_FLAGS flags, ref FREE_IMAGE_FORMAT format)
1025  {
1026  // check if file exists
1027  if (!File.Exists(filename))
1028  {
1029  throw new FileNotFoundException(filename + " could not be found.");
1030  }
1031  FIBITMAP dib = new FIBITMAP();
1032  if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
1033  {
1034  // query all plugins to see if one can read the file
1035  format = GetFileType(filename, 0);
1036  }
1037  // check if the plugin is capable of loading files
1038  if (FIFSupportsReading(format))
1039  {
1040  dib = Load(format, filename, flags);
1041  }
1042  return dib;
1043  }
1044 
1045  /// <summary>
1046  /// Loads a .NET <see cref="System.Drawing.Bitmap"/> from a file.
1047  /// </summary>
1048  /// <param name="filename">Name of the file to be loaded.</param>
1049  /// <param name="format">Format of the image. If the format should be taken from the
1050  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
1051  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1052  /// <returns>The loaded .NET <see cref="System.Drawing.Bitmap"/>.</returns>
1053  /// <exception cref="FileNotFoundException">
1054  /// <paramref name="filename"/> does not exists.</exception>
1055  /// <exception cref="ArgumentException">
1056  /// The image type of the image is not <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/>.</exception>
1057  public static Bitmap LoadBitmap(string filename, FREE_IMAGE_LOAD_FLAGS flags, ref FREE_IMAGE_FORMAT format)
1058  {
1059  FIBITMAP dib = LoadEx(filename, flags, ref format);
1060  Bitmap result = GetBitmap(dib, true);
1061  Unload(dib);
1062  return result;
1063  }
1064 
1065  /// <summary>
1066  /// Deletes a previously loaded FreeImage bitmap from memory and resets the handle to 0.
1067  /// </summary>
1068  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1069  public static void UnloadEx(ref FIBITMAP dib)
1070  {
1071  if (!dib.IsNull)
1072  {
1073  Unload(dib);
1074  dib.SetNull();
1075  }
1076  }
1077 
1078  /// <summary>
1079  /// Saves a previously loaded FreeImage bitmap to a file.
1080  /// The format is taken off the filename.
1081  /// If no suitable format was found false will be returned.
1082  /// </summary>
1083  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1084  /// <param name="filename">The complete name of the file to save to.
1085  /// The extension will be corrected if it is no valid extension for the
1086  /// selected format or if no extension was specified.</param>
1087  /// <returns>Returns true on success, false on failure.</returns>
1088  /// <exception cref="ArgumentNullException">
1089  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1090  public static bool SaveEx(FIBITMAP dib, string filename)
1091  {
1092  return SaveEx(
1093  ref dib,
1094  filename,
1095  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
1096  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1097  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1098  false);
1099  }
1100 
1101  /// <summary>
1102  /// Saves a previously loaded FreeImage bitmap to a file.
1103  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
1104  /// the format is taken off the filename.
1105  /// If no suitable format was found false will be returned.
1106  /// </summary>
1107  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1108  /// <param name="filename">The complete name of the file to save to.
1109  /// The extension will be corrected if it is no valid extension for the
1110  /// selected format or if no extension was specified.</param>
1111  /// <param name="format">Format of the image. If the format should be taken from the
1112  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
1113  /// <returns>Returns true on success, false on failure.</returns>
1114  /// <exception cref="ArgumentNullException">
1115  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1116  public static bool SaveEx(
1117  FIBITMAP dib,
1118  string filename,
1119  FREE_IMAGE_FORMAT format)
1120  {
1121  return SaveEx(
1122  ref dib,
1123  filename,
1124  format,
1125  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1126  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1127  false);
1128  }
1129 
1130  /// <summary>
1131  /// Saves a previously loaded FreeImage bitmap to a file.
1132  /// The format is taken off the filename.
1133  /// If no suitable format was found false will be returned.
1134  /// </summary>
1135  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1136  /// <param name="filename">The complete name of the file to save to.
1137  /// The extension will be corrected if it is no valid extension for the
1138  /// selected format or if no extension was specified.</param>
1139  /// <param name="unloadSource">When true the structure will be unloaded on success.
1140  /// If the function failed and returned false, the bitmap was not unloaded.</param>
1141  /// <returns>Returns true on success, false on failure.</returns>
1142  /// <exception cref="ArgumentNullException">
1143  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1144  public static bool SaveEx(
1145  ref FIBITMAP dib,
1146  string filename,
1147  bool unloadSource)
1148  {
1149  return SaveEx(
1150  ref dib,
1151  filename,
1152  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
1153  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1154  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1155  unloadSource);
1156  }
1157 
1158  /// <summary>
1159  /// Saves a previously loaded FreeImage bitmap to a file.
1160  /// The format is taken off the filename.
1161  /// If no suitable format was found false will be returned.
1162  /// Save flags can be provided by the flags parameter.
1163  /// </summary>
1164  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1165  /// <param name="filename">The complete name of the file to save to.
1166  /// The extension will be corrected if it is no valid extension for the
1167  /// selected format or if no extension was specified</param>
1168  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1169  /// <returns>Returns true on success, false on failure.</returns>
1170  /// <exception cref="ArgumentNullException">
1171  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1172  public static bool SaveEx(
1173  FIBITMAP dib,
1174  string filename,
1175  FREE_IMAGE_SAVE_FLAGS flags)
1176  {
1177  return SaveEx(
1178  ref dib,
1179  filename,
1180  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
1181  flags,
1182  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1183  false);
1184  }
1185 
1186  /// <summary>
1187  /// Saves a previously loaded FreeImage bitmap to a file.
1188  /// The format is taken off the filename.
1189  /// If no suitable format was found false will be returned.
1190  /// Save flags can be provided by the flags parameter.
1191  /// </summary>
1192  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1193  /// <param name="filename">The complete name of the file to save to.
1194  /// The extension will be corrected if it is no valid extension for the
1195  /// selected format or if no extension was specified.</param>
1196  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1197  /// <param name="unloadSource">When true the structure will be unloaded on success.
1198  /// If the function failed and returned false, the bitmap was not unloaded.</param>
1199  /// <returns>Returns true on success, false on failure.</returns>
1200  /// <exception cref="ArgumentNullException">
1201  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1202  public static bool SaveEx(
1203  ref FIBITMAP dib,
1204  string filename,
1205  FREE_IMAGE_SAVE_FLAGS flags,
1206  bool unloadSource)
1207  {
1208  return SaveEx(
1209  ref dib,
1210  filename,
1211  FREE_IMAGE_FORMAT.FIF_UNKNOWN,
1212  flags,
1213  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1214  unloadSource);
1215  }
1216 
1217  /// <summary>
1218  /// Saves a previously loaded FreeImage bitmap to a file.
1219  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
1220  /// the format is taken off the filename.
1221  /// If no suitable format was found false will be returned.
1222  /// </summary>
1223  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1224  /// <param name="filename">The complete name of the file to save to.
1225  /// The extension will be corrected if it is no valid extension for the
1226  /// selected format or if no extension was specified.</param>
1227  /// <param name="format">Format of the image. If the format should be taken from the
1228  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
1229  /// <param name="unloadSource">When true the structure will be unloaded on success.
1230  /// If the function failed and returned false, the bitmap was not unloaded.</param>
1231  /// <returns>Returns true on success, false on failure.</returns>
1232  /// <exception cref="ArgumentNullException">
1233  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1234  public static bool SaveEx(
1235  ref FIBITMAP dib,
1236  string filename,
1237  FREE_IMAGE_FORMAT format,
1238  bool unloadSource)
1239  {
1240  return SaveEx(
1241  ref dib,
1242  filename,
1243  format,
1244  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1245  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1246  unloadSource);
1247  }
1248 
1249  /// <summary>
1250  /// Saves a previously loaded FreeImage bitmap to a file.
1251  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
1252  /// the format is taken off the filename.
1253  /// If no suitable format was found false will be returned.
1254  /// Save flags can be provided by the flags parameter.
1255  /// </summary>
1256  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1257  /// <param name="filename">The complete name of the file to save to.
1258  /// The extension will be corrected if it is no valid extension for the
1259  /// selected format or if no extension was specified.</param>
1260  /// <param name="format">Format of the image. If the format should be taken from the
1261  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
1262  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1263  /// <returns>Returns true on success, false on failure.</returns>
1264  /// <exception cref="ArgumentNullException">
1265  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1266  public static bool SaveEx(
1267  FIBITMAP dib,
1268  string filename,
1269  FREE_IMAGE_FORMAT format,
1270  FREE_IMAGE_SAVE_FLAGS flags)
1271  {
1272  return SaveEx(
1273  ref dib,
1274  filename,
1275  format,
1276  flags,
1277  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1278  false);
1279  }
1280 
1281  /// <summary>
1282  /// Saves a previously loaded FreeImage bitmap to a file.
1283  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
1284  /// the format is taken off the filename.
1285  /// If no suitable format was found false will be returned.
1286  /// Save flags can be provided by the flags parameter.
1287  /// The bitmaps color depth can be set by 'colorDepth'.
1288  /// If set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> a suitable color depth
1289  /// will be taken if available.
1290  /// </summary>
1291  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1292  /// <param name="filename">The complete name of the file to save to.
1293  /// The extension will be corrected if it is no valid extension for the
1294  /// selected format or if no extension was specified.</param>
1295  /// <param name="format">Format of the image. If the format should be taken from the
1296  /// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
1297  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1298  /// <param name="colorDepth">The new color depth of the bitmap.
1299  /// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if Save should take the
1300  /// best suitable color depth.
1301  /// If a color depth is selected that the provided format cannot write an
1302  /// error-message will be thrown.</param>
1303  /// <param name="unloadSource">When true the structure will be unloaded on success.
1304  /// If the function failed and returned false, the bitmap was not unloaded.</param>
1305  /// <returns>Returns true on success, false on failure.</returns>
1306  /// <exception cref="ArgumentException">
1307  /// A direct color conversion failed.</exception>
1308  /// <exception cref="ArgumentNullException">
1309  /// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
1310  public static bool SaveEx(
1311  ref FIBITMAP dib,
1312  string filename,
1313  FREE_IMAGE_FORMAT format,
1314  FREE_IMAGE_SAVE_FLAGS flags,
1315  FREE_IMAGE_COLOR_DEPTH colorDepth,
1316  bool unloadSource)
1317  {
1318  if (dib.IsNull)
1319  {
1320  throw new ArgumentNullException("dib");
1321  }
1322  if (filename == null)
1323  {
1324  throw new ArgumentNullException("filename");
1325  }
1326  bool result = false;
1327  // Gets format from filename if the format is unknown
1328  if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
1329  {
1330  format = GetFIFFromFilename(filename);
1331  }
1332  if (format != FREE_IMAGE_FORMAT.FIF_UNKNOWN)
1333  {
1334  // Checks writing support
1335  if (FIFSupportsWriting(format) && FIFSupportsExportType(format, GetImageType(dib)))
1336  {
1337  // Check valid filename and correct it if needed
1338  if (!IsFilenameValidForFIF(format, filename))
1339  {
1340  string extension = GetPrimaryExtensionFromFIF(format);
1341  filename = Path.ChangeExtension(filename, extension);
1342  }
1343 
1344  FIBITMAP dibToSave = PrepareBitmapColorDepth(dib, format, colorDepth);
1345  try
1346  {
1347  result = Save(format, dibToSave, filename, flags);
1348  }
1349  finally
1350  {
1351  // Always unload a temporary created bitmap.
1352  if (dibToSave != dib)
1353  {
1354  UnloadEx(ref dibToSave);
1355  }
1356  // On success unload the bitmap
1357  if (result && unloadSource)
1358  {
1359  UnloadEx(ref dib);
1360  }
1361  }
1362  }
1363  }
1364  return result;
1365  }
1366 
1367  /// <summary>
1368  /// Loads a FreeImage bitmap.
1369  /// The stream must be set to the correct position before calling LoadFromStream.
1370  /// </summary>
1371  /// <param name="stream">The stream to read from.</param>
1372  /// <returns>Handle to a FreeImage bitmap.</returns>
1373  /// <exception cref="ArgumentNullException">
1374  /// <paramref name="stream"/> is null.</exception>
1375  /// <exception cref="ArgumentException">
1376  /// <paramref name="stream"/> is not capable of reading.</exception>
1377  public static FIBITMAP LoadFromStream(Stream stream)
1378  {
1379  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1380  return LoadFromStream(stream, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
1381  }
1382 
1383  /// <summary>
1384  /// Loads a FreeImage bitmap.
1385  /// The stream must be set to the correct position before calling LoadFromStream.
1386  /// </summary>
1387  /// <param name="stream">The stream to read from.</param>
1388  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1389  /// <returns>Handle to a FreeImage bitmap.</returns>
1390  /// <exception cref="ArgumentNullException">
1391  /// <paramref name="stream"/> is null.</exception>
1392  /// <exception cref="ArgumentException">
1393  /// <paramref name="stream"/> is not capable of reading.</exception>
1394  public static FIBITMAP LoadFromStream(Stream stream, FREE_IMAGE_LOAD_FLAGS flags)
1395  {
1396  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1397  return LoadFromStream(stream, flags, ref format);
1398  }
1399 
1400  /// <summary>
1401  /// Loads a FreeImage bitmap.
1402  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the
1403  /// bitmaps real format is being analysed.
1404  /// The stream must be set to the correct position before calling LoadFromStream.
1405  /// </summary>
1406  /// <param name="stream">The stream to read from.</param>
1407  /// <param name="format">Format of the image. If the format is unknown use
1408  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
1409  /// In case a suitable format was found by LoadFromStream it will be returned in format.</param>
1410  /// <returns>Handle to a FreeImage bitmap.</returns>
1411  /// <exception cref="ArgumentNullException">
1412  /// <paramref name="stream"/> is null.</exception>
1413  /// <exception cref="ArgumentException">
1414  /// <paramref name="stream"/> is not capable of reading.</exception>
1415  public static FIBITMAP LoadFromStream(Stream stream, ref FREE_IMAGE_FORMAT format)
1416  {
1417  return LoadFromStream(stream, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
1418  }
1419 
1420  /// <summary>
1421  /// Loads a FreeImage bitmap.
1422  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
1423  /// the bitmaps real format is being analysed.
1424  /// The stream must be set to the correct position before calling LoadFromStream.
1425  /// </summary>
1426  /// <param name="stream">The stream to read from.</param>
1427  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1428  /// <param name="format">Format of the image. If the format is unknown use
1429  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
1430  /// In case a suitable format was found by LoadFromStream it will be returned in format.</param>
1431  /// <returns>Handle to a FreeImage bitmap.</returns>
1432  /// <exception cref="ArgumentNullException">
1433  /// <paramref name="stream"/> is null.</exception>
1434  /// <exception cref="ArgumentException">
1435  /// <paramref name="stream"/> is not capable of reading.</exception>
1436  public static FIBITMAP LoadFromStream(
1437  Stream stream,
1438  FREE_IMAGE_LOAD_FLAGS flags,
1439  ref FREE_IMAGE_FORMAT format)
1440  {
1441  if (stream == null)
1442  {
1443  throw new ArgumentNullException("stream");
1444  }
1445  if (!stream.CanRead)
1446  {
1447  throw new ArgumentException("stream is not capable of reading.");
1448  }
1449  // Wrap the source stream if it is unable to seek (which is required by FreeImage)
1450  stream = (stream.CanSeek) ? stream : new StreamWrapper(stream, true);
1451 
1452  stream.Position = 0L;
1453  if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
1454  {
1455  // Get the format of the bitmap
1456  format = GetFileTypeFromStream(stream);
1457  // Restore the streams position
1458  stream.Position = 0L;
1459  }
1460  if (!FIFSupportsReading(format))
1461  {
1462  return FIBITMAP.Zero;
1463  }
1464  // Create a 'FreeImageIO' structure for calling 'LoadFromHandle'
1465  // using the internal structure 'FreeImageStreamIO'.
1466  FreeImageIO io = FreeImageStreamIO.io;
1467  using (fi_handle handle = new fi_handle(stream))
1468  {
1469  return LoadFromHandle(format, ref io, handle, flags);
1470  }
1471  }
1472 
1473  /// <summary>
1474  /// Saves a previously loaded FreeImage bitmap to a stream.
1475  /// The stream must be set to the correct position before calling SaveToStream.
1476  /// </summary>
1477  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1478  /// <param name="stream">The stream to write to.</param>
1479  /// <param name="format">Format of the image.</param>
1480  /// <returns>Returns true on success, false on failure.</returns>
1481  /// <exception cref="ArgumentNullException">
1482  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1483  /// <exception cref="ArgumentException">
1484  /// <paramref name="stream"/> cannot write.</exception>
1485  public static bool SaveToStream(
1486  FIBITMAP dib,
1487  Stream stream,
1488  FREE_IMAGE_FORMAT format)
1489  {
1490  return SaveToStream(
1491  ref dib,
1492  stream,
1493  format,
1494  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1495  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1496  false);
1497  }
1498 
1499  /// <summary>
1500  /// Saves a previously loaded FreeImage bitmap to a stream.
1501  /// The stream must be set to the correct position before calling SaveToStream.
1502  /// </summary>
1503  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1504  /// <param name="stream">The stream to write to.</param>
1505  /// <param name="format">Format of the image.</param>
1506  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
1507  /// <returns>Returns true on success, false on failure.</returns>
1508  /// <exception cref="ArgumentNullException">
1509  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1510  /// <exception cref="ArgumentException">
1511  /// <paramref name="stream"/> cannot write.</exception>
1512  public static bool SaveToStream(
1513  ref FIBITMAP dib,
1514  Stream stream,
1515  FREE_IMAGE_FORMAT format,
1516  bool unloadSource)
1517  {
1518  return SaveToStream(
1519  ref dib,
1520  stream,
1521  format,
1522  FREE_IMAGE_SAVE_FLAGS.DEFAULT,
1523  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1524  unloadSource);
1525  }
1526 
1527  /// <summary>
1528  /// Saves a previously loaded FreeImage bitmap to a stream.
1529  /// The stream must be set to the correct position before calling SaveToStream.
1530  /// </summary>
1531  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1532  /// <param name="stream">The stream to write to.</param>
1533  /// <param name="format">Format of the image.</param>
1534  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1535  /// <returns>Returns true on success, false on failure.</returns>
1536  /// <exception cref="ArgumentNullException">
1537  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1538  /// <exception cref="ArgumentException">
1539  /// <paramref name="stream"/> cannot write.</exception>
1540  public static bool SaveToStream(
1541  FIBITMAP dib,
1542  Stream stream,
1543  FREE_IMAGE_FORMAT format,
1544  FREE_IMAGE_SAVE_FLAGS flags)
1545  {
1546  return SaveToStream(
1547  ref dib,
1548  stream,
1549  format,
1550  flags,
1551  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1552  false);
1553  }
1554 
1555  /// <summary>
1556  /// Saves a previously loaded FreeImage bitmap to a stream.
1557  /// The stream must be set to the correct position before calling SaveToStream.
1558  /// </summary>
1559  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1560  /// <param name="stream">The stream to write to.</param>
1561  /// <param name="format">Format of the image.</param>
1562  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1563  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
1564  /// <returns>Returns true on success, false on failure.</returns>
1565  /// <exception cref="ArgumentNullException">
1566  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1567  /// <exception cref="ArgumentException">
1568  /// <paramref name="stream"/> cannot write.</exception>
1569  public static bool SaveToStream(
1570  ref FIBITMAP dib,
1571  Stream stream,
1572  FREE_IMAGE_FORMAT format,
1573  FREE_IMAGE_SAVE_FLAGS flags,
1574  bool unloadSource)
1575  {
1576  return SaveToStream(
1577  ref dib, stream,
1578  format,
1579  flags,
1580  FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
1581  unloadSource);
1582  }
1583 
1584  /// <summary>
1585  /// Saves a previously loaded FreeImage bitmap to a stream.
1586  /// The stream must be set to the correct position before calling SaveToStream.
1587  /// </summary>
1588  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1589  /// <param name="stream">The stream to write to.</param>
1590  /// <param name="format">Format of the image.</param>
1591  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1592  /// <param name="colorDepth">The new color depth of the bitmap.
1593  /// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if SaveToStream should
1594  /// take the best suitable color depth.
1595  /// If a color depth is selected that the provided format cannot write an
1596  /// error-message will be thrown.</param>
1597  /// <returns>Returns true on success, false on failure.</returns>
1598  /// <exception cref="ArgumentNullException">
1599  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1600  /// <exception cref="ArgumentException">
1601  /// <paramref name="stream"/> cannot write.</exception>
1602  public static bool SaveToStream(
1603  FIBITMAP dib,
1604  Stream stream,
1605  FREE_IMAGE_FORMAT format,
1606  FREE_IMAGE_SAVE_FLAGS flags,
1607  FREE_IMAGE_COLOR_DEPTH colorDepth)
1608  {
1609  return SaveToStream(
1610  ref dib,
1611  stream,
1612  format,
1613  flags,
1614  colorDepth,
1615  false);
1616  }
1617 
1618  /// <summary>
1619  /// Saves a previously loaded FreeImage bitmap to a stream.
1620  /// The stream must be set to the correct position before calling SaveToStream.
1621  /// </summary>
1622  /// <param name="dib">Handle to a FreeImage bitmap.</param>
1623  /// <param name="stream">The stream to write to.</param>
1624  /// <param name="format">Format of the image.</param>
1625  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1626  /// <param name="colorDepth">The new color depth of the bitmap.
1627  /// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if SaveToStream should
1628  /// take the best suitable color depth.
1629  /// If a color depth is selected that the provided format cannot write an
1630  /// error-message will be thrown.</param>
1631  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
1632  /// <returns>Returns true on success, false on failure.</returns>
1633  /// <exception cref="ArgumentNullException">
1634  /// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
1635  /// <exception cref="ArgumentException">
1636  /// <paramref name="stream"/> cannot write.</exception>
1637  public static bool SaveToStream(
1638  ref FIBITMAP dib,
1639  Stream stream,
1640  FREE_IMAGE_FORMAT format,
1641  FREE_IMAGE_SAVE_FLAGS flags,
1642  FREE_IMAGE_COLOR_DEPTH colorDepth,
1643  bool unloadSource)
1644  {
1645  if (dib.IsNull)
1646  {
1647  throw new ArgumentNullException("dib");
1648  }
1649  if (stream == null)
1650  {
1651  throw new ArgumentNullException("stream");
1652  }
1653  if (!stream.CanWrite)
1654  {
1655  throw new ArgumentException("stream is not capable of writing.");
1656  }
1657  if ((!FIFSupportsWriting(format)) || (!FIFSupportsExportType(format, GetImageType(dib))))
1658  {
1659  return false;
1660  }
1661 
1662  FIBITMAP dibToSave = PrepareBitmapColorDepth(dib, format, colorDepth);
1663  bool result = false;
1664 
1665  try
1666  {
1667  // Create a 'FreeImageIO' structure for calling 'SaveToHandle'
1668  FreeImageIO io = FreeImageStreamIO.io;
1669 
1670  using (fi_handle handle = new fi_handle(stream))
1671  {
1672  result = SaveToHandle(format, dibToSave, ref io, handle, flags);
1673  }
1674  }
1675  finally
1676  {
1677  // Always unload a temporary created bitmap.
1678  if (dibToSave != dib)
1679  {
1680  UnloadEx(ref dibToSave);
1681  }
1682  // On success unload the bitmap
1683  if (result && unloadSource)
1684  {
1685  UnloadEx(ref dib);
1686  }
1687  }
1688 
1689  return result;
1690  }
1691 
1692  #endregion
1693 
1694  #region Plugin functions
1695 
1696  /// <summary>
1697  /// Checks if an extension is valid for a certain format.
1698  /// </summary>
1699  /// <param name="fif">The desired format.</param>
1700  /// <param name="extension">The desired extension.</param>
1701  /// <returns>True if the extension is valid for the given format, false otherwise.</returns>
1702  /// <exception cref="ArgumentNullException">
1703  /// <paramref name="extension"/> is null.</exception>
1704  public static bool IsExtensionValidForFIF(FREE_IMAGE_FORMAT fif, string extension)
1705  {
1706  return IsExtensionValidForFIF(fif, extension, StringComparison.CurrentCultureIgnoreCase);
1707  }
1708 
1709  /// <summary>
1710  /// Checks if an extension is valid for a certain format.
1711  /// </summary>
1712  /// <param name="fif">The desired format.</param>
1713  /// <param name="extension">The desired extension.</param>
1714  /// <param name="comparisonType">The string comparison type.</param>
1715  /// <returns>True if the extension is valid for the given format, false otherwise.</returns>
1716  /// <exception cref="ArgumentNullException">
1717  /// <paramref name="extension"/> is null.</exception>
1718  public static bool IsExtensionValidForFIF(FREE_IMAGE_FORMAT fif, string extension, StringComparison comparisonType)
1719  {
1720  if (extension == null)
1721  {
1722  throw new ArgumentNullException("extension");
1723  }
1724  bool result = false;
1725  // Split up the string and compare each with the given extension
1726  string tempList = GetFIFExtensionList(fif);
1727  if (tempList != null)
1728  {
1729  string[] extensionList = tempList.Split(',');
1730  foreach (string ext in extensionList)
1731  {
1732  if (extension.Equals(ext, comparisonType))
1733  {
1734  result = true;
1735  break;
1736  }
1737  }
1738  }
1739  return result;
1740  }
1741 
1742  /// <summary>
1743  /// Checks if a filename is valid for a certain format.
1744  /// </summary>
1745  /// <param name="fif">The desired format.</param>
1746  /// <param name="filename">The desired filename.</param>
1747  /// <returns>True if the filename is valid for the given format, false otherwise.</returns>
1748  /// <exception cref="ArgumentNullException">
1749  /// <paramref name="filename"/> is null.</exception>
1750  public static bool IsFilenameValidForFIF(FREE_IMAGE_FORMAT fif, string filename)
1751  {
1752  return IsFilenameValidForFIF(fif, filename, StringComparison.CurrentCultureIgnoreCase);
1753  }
1754 
1755  /// <summary>
1756  /// Checks if a filename is valid for a certain format.
1757  /// </summary>
1758  /// <param name="fif">The desired format.</param>
1759  /// <param name="filename">The desired filename.</param>
1760  /// <param name="comparisonType">The string comparison type.</param>
1761  /// <returns>True if the filename is valid for the given format, false otherwise.</returns>
1762  /// <exception cref="ArgumentNullException">
1763  /// <paramref name="filename"/> is null.</exception>
1764  public static bool IsFilenameValidForFIF(FREE_IMAGE_FORMAT fif, string filename, StringComparison comparisonType)
1765  {
1766  if (filename == null)
1767  {
1768  throw new ArgumentNullException("filename");
1769  }
1770  bool result = false;
1771  // Extract the filenames extension if it exists
1772  string extension = Path.GetExtension(filename);
1773  if (extension.Length != 0)
1774  {
1775  extension = extension.Remove(0, 1);
1776  result = IsExtensionValidForFIF(fif, extension, comparisonType);
1777  }
1778  return result;
1779  }
1780 
1781  /// <summary>
1782  /// This function returns the primary (main or most commonly used?) extension of a certain
1783  /// image format (fif). This is done by returning the first of all possible extensions
1784  /// returned by GetFIFExtensionList().
1785  /// That assumes, that the plugin returns the extensions in ordered form.</summary>
1786  /// <param name="fif">The image format to obtain the primary extension for.</param>
1787  /// <returns>The primary extension of the specified image format.</returns>
1788  public static string GetPrimaryExtensionFromFIF(FREE_IMAGE_FORMAT fif)
1789  {
1790  string result = null;
1791  string extensions = GetFIFExtensionList(fif);
1792  if (extensions != null)
1793  {
1794  int position = extensions.IndexOf(',');
1795  if (position < 0)
1796  {
1797  result = extensions;
1798  }
1799  else
1800  {
1801  result = extensions.Substring(0, position);
1802  }
1803  }
1804  return result;
1805  }
1806 
1807  #endregion
1808 
1809  #region Multipage functions
1810 
1811  /// <summary>
1812  /// Loads a FreeImage multi-paged bitmap.
1813  /// </summary>
1814  /// <param name="filename">The complete name of the file to load.</param>
1815  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1816  /// <exception cref="FileNotFoundException">
1817  /// <paramref name="filename"/> does not exists while opening.</exception>
1818  public static FIMULTIBITMAP OpenMultiBitmapEx(string filename)
1819  {
1820  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1821  return OpenMultiBitmapEx(
1822  filename,
1823  ref format,
1824  FREE_IMAGE_LOAD_FLAGS.DEFAULT,
1825  false,
1826  false,
1827  false);
1828  }
1829 
1830  /// <summary>
1831  /// Loads a FreeImage multi-paged bitmap.
1832  /// </summary>
1833  /// <param name="filename">The complete name of the file to load.</param>
1834  /// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
1835  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1836  /// <exception cref="FileNotFoundException">
1837  /// <paramref name="filename"/> does not exists while opening.</exception>
1838  public static FIMULTIBITMAP OpenMultiBitmapEx(string filename, bool keep_cache_in_memory)
1839  {
1840  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1841  return OpenMultiBitmapEx(
1842  filename,
1843  ref format,
1844  FREE_IMAGE_LOAD_FLAGS.DEFAULT,
1845  false,
1846  false,
1847  keep_cache_in_memory);
1848  }
1849 
1850  /// <summary>
1851  /// Loads a FreeImage multi-paged bitmap.
1852  /// </summary>
1853  /// <param name="filename">The complete name of the file to load.</param>
1854  /// <param name="read_only">When true the bitmap will be loaded read only.</param>
1855  /// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
1856  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1857  /// <exception cref="FileNotFoundException">
1858  /// <paramref name="filename"/> does not exists while opening.</exception>
1859  public static FIMULTIBITMAP OpenMultiBitmapEx(
1860  string filename,
1861  bool read_only,
1862  bool keep_cache_in_memory)
1863  {
1864  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1865  return OpenMultiBitmapEx(
1866  filename,
1867  ref format,
1868  FREE_IMAGE_LOAD_FLAGS.DEFAULT,
1869  false,
1870  read_only,
1871  keep_cache_in_memory);
1872  }
1873 
1874  /// <summary>
1875  /// Loads a FreeImage multi-paged bitmap.
1876  /// </summary>
1877  /// <param name="filename">The complete name of the file to load.</param>
1878  /// <param name="create_new">When true a new bitmap is created.</param>
1879  /// <param name="read_only">When true the bitmap will be loaded read only.</param>
1880  /// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
1881  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1882  /// <exception cref="FileNotFoundException">
1883  /// <paramref name="filename"/> does not exists while opening.</exception>
1884  public static FIMULTIBITMAP OpenMultiBitmapEx(
1885  string filename,
1886  bool create_new,
1887  bool read_only,
1888  bool keep_cache_in_memory)
1889  {
1890  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1891  return OpenMultiBitmapEx(
1892  filename,
1893  ref format,
1894  FREE_IMAGE_LOAD_FLAGS.DEFAULT,
1895  create_new,
1896  read_only,
1897  keep_cache_in_memory);
1898  }
1899 
1900  /// <summary>
1901  /// Loads a FreeImage multi-paged bitmap.
1902  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files real
1903  /// format is being analysed. If no plugin can read the file, format remains
1904  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
1905  /// </summary>
1906  /// <param name="filename">The complete name of the file to load.</param>
1907  /// <param name="format">Format of the image. If the format is unknown use
1908  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
1909  /// In case a suitable format was found by LoadEx it will be returned in format.</param>
1910  /// <param name="create_new">When true a new bitmap is created.</param>
1911  /// <param name="read_only">When true the bitmap will be loaded read only.</param>
1912  /// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
1913  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1914  /// <exception cref="FileNotFoundException">
1915  /// <paramref name="filename"/> does not exists while opening.</exception>
1916  public static FIMULTIBITMAP OpenMultiBitmapEx(
1917  string filename,
1918  ref FREE_IMAGE_FORMAT format,
1919  bool create_new,
1920  bool read_only,
1921  bool keep_cache_in_memory)
1922  {
1923  return OpenMultiBitmapEx(
1924  filename,
1925  ref format,
1926  FREE_IMAGE_LOAD_FLAGS.DEFAULT,
1927  create_new,
1928  read_only,
1929  keep_cache_in_memory);
1930  }
1931 
1932  /// <summary>
1933  /// Loads a FreeImage multi-paged bitmap.
1934  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
1935  /// real format is being analysed. If no plugin can read the file, format remains
1936  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
1937  /// Load flags can be provided by the flags parameter.
1938  /// </summary>
1939  /// <param name="filename">The complete name of the file to load.</param>
1940  /// <param name="format">Format of the image. If the format is unknown use
1941  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
1942  /// In case a suitable format was found by LoadEx it will be returned in format.</param>
1943  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1944  /// <param name="create_new">When true a new bitmap is created.</param>
1945  /// <param name="read_only">When true the bitmap will be loaded read only.</param>
1946  /// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
1947  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1948  /// <exception cref="FileNotFoundException">
1949  /// <paramref name="filename"/> does not exists while opening.</exception>
1950  public static FIMULTIBITMAP OpenMultiBitmapEx(
1951  string filename,
1952  ref FREE_IMAGE_FORMAT format,
1953  FREE_IMAGE_LOAD_FLAGS flags,
1954  bool create_new,
1955  bool read_only,
1956  bool keep_cache_in_memory)
1957  {
1958  if (!File.Exists(filename) && !create_new)
1959  {
1960  throw new FileNotFoundException(filename + " could not be found.");
1961  }
1962  if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
1963  {
1964  // Check if a plugin can read the data
1965  format = GetFileType(filename, 0);
1966  }
1967  FIMULTIBITMAP dib = new FIMULTIBITMAP();
1968  if (FIFSupportsReading(format))
1969  {
1970  dib = OpenMultiBitmap(format, filename, create_new, read_only, keep_cache_in_memory, flags);
1971  }
1972  return dib;
1973  }
1974 
1975  /// <summary>
1976  /// Loads a FreeImage multi-paged bitmap.
1977  /// </summary>
1978  /// <param name="stream">The stream to load the bitmap from.</param>
1979  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1980  public static FIMULTIBITMAP OpenMultiBitmapFromStream(Stream stream)
1981  {
1982  FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
1983  return OpenMultiBitmapFromStream(stream, ref format, FREE_IMAGE_LOAD_FLAGS.DEFAULT);
1984  }
1985 
1986  /// <summary>
1987  /// Loads a FreeImage multi-paged bitmap.
1988  /// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
1989  /// real format is being analysed. If no plugin can read the file, format remains
1990  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
1991  /// Load flags can be provided by the flags parameter.
1992  /// </summary>
1993  /// <param name="stream">The stream to load the bitmap from.</param>
1994  /// <param name="format">Format of the image. If the format is unknown use
1995  /// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/></param>.
1996  /// <param name="flags">Flags to enable or disable plugin-features.</param>
1997  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
1998  public static FIMULTIBITMAP OpenMultiBitmapFromStream(Stream stream, ref FREE_IMAGE_FORMAT format, FREE_IMAGE_LOAD_FLAGS flags)
1999  {
2000  if (stream == null)
2001  return FIMULTIBITMAP.Zero;
2002 
2003  if (!stream.CanSeek)
2004  stream = new StreamWrapper(stream, true);
2005 
2006  FIMULTIBITMAP mdib = FIMULTIBITMAP.Zero;
2007  FreeImageIO io = FreeImageStreamIO.io;
2008  fi_handle handle = new fi_handle(stream);
2009 
2010  try
2011  {
2012  if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
2013  {
2014  format = GetFileTypeFromHandle(ref io, handle, checked((int)stream.Length));
2015  }
2016 
2017  mdib = OpenMultiBitmapFromHandle(format, ref io, handle, flags);
2018 
2019  if (mdib.IsNull)
2020  {
2021  handle.Dispose();
2022  }
2023  else
2024  {
2025  lock (streamHandles)
2026  {
2027  streamHandles.Add(mdib, handle);
2028  }
2029  }
2030 
2031  return mdib;
2032  }
2033  catch
2034  {
2035  if (!mdib.IsNull)
2036  CloseMultiBitmap(mdib, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
2037 
2038  if (handle != null)
2039  handle.Dispose();
2040 
2041  throw;
2042  }
2043  }
2044 
2045  /// <summary>
2046  /// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only, applies any changes made to it.
2047  /// </summary>
2048  /// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
2049  /// <param name="flags">Flags to enable or disable plugin-features.</param>
2050  /// <returns>Returns true on success, false on failure.</returns>
2051  public static bool CloseMultiBitmap(FIMULTIBITMAP bitmap, FREE_IMAGE_SAVE_FLAGS flags)
2052  {
2053  if (CloseMultiBitmap_(bitmap, flags))
2054  {
2055  fi_handle handle;
2056  lock (streamHandles)
2057  {
2058  if (streamHandles.TryGetValue(bitmap, out handle))
2059  {
2060  streamHandles.Remove(bitmap);
2061  handle.Dispose();
2062  }
2063  }
2064  return true;
2065  }
2066  return false;
2067  }
2068 
2069  /// <summary>
2070  /// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only,
2071  /// applies any changes made to it.
2072  /// On success the handle will be reset to null.
2073  /// </summary>
2074  /// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
2075  /// <returns>Returns true on success, false on failure.</returns>
2076  public static bool CloseMultiBitmapEx(ref FIMULTIBITMAP bitmap)
2077  {
2078  return CloseMultiBitmapEx(ref bitmap, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
2079  }
2080 
2081  /// <summary>
2082  /// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only,
2083  /// applies any changes made to it.
2084  /// On success the handle will be reset to null.
2085  /// </summary>
2086  /// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
2087  /// <param name="flags">Flags to enable or disable plugin-features.</param>
2088  /// <returns>Returns true on success, false on failure.</returns>
2089  public static bool CloseMultiBitmapEx(ref FIMULTIBITMAP bitmap, FREE_IMAGE_SAVE_FLAGS flags)
2090  {
2091  bool result = false;
2092  if (!bitmap.IsNull)
2093  {
2094  if (CloseMultiBitmap(bitmap, flags))
2095  {
2096  bitmap.SetNull();
2097  result = true;
2098  }
2099  }
2100  return result;
2101  }
2102 
2103  /// <summary>
2104  /// Retrieves the number of pages that are locked in a multi-paged bitmap.
2105  /// </summary>
2106  /// <param name="dib">Handle to a FreeImage multi-paged bitmap.</param>
2107  /// <returns>Number of locked pages.</returns>
2108  /// <exception cref="ArgumentNullException">
2109  /// <paramref name="dib"/> is null.</exception>
2110  public static int GetLockedPageCount(FIMULTIBITMAP dib)
2111  {
2112  if (dib.IsNull)
2113  {
2114  throw new ArgumentNullException("dib");
2115  }
2116  int result = 0;
2117  GetLockedPageNumbers(dib, null, ref result);
2118  return result;
2119  }
2120 
2121  /// <summary>
2122  /// Retrieves a list locked pages of a multi-paged bitmap.
2123  /// </summary>
2124  /// <param name="dib">Handle to a FreeImage multi-paged bitmap.</param>
2125  /// <returns>List containing the indexes of the locked pages.</returns>
2126  /// <exception cref="ArgumentNullException">
2127  /// <paramref name="dib"/> is null.</exception>
2128  public static int[] GetLockedPages(FIMULTIBITMAP dib)
2129  {
2130  if (dib.IsNull)
2131  {
2132  throw new ArgumentNullException("dib");
2133  }
2134  // Get the number of pages and create an array to save the information
2135  int count = 0;
2136  int[] result = null;
2137  // Get count
2138  if (GetLockedPageNumbers(dib, result, ref count))
2139  {
2140  result = new int[count];
2141  // Fill array
2142  if (!GetLockedPageNumbers(dib, result, ref count))
2143  {
2144  result = null;
2145  }
2146  }
2147  return result;
2148  }
2149 
2150  /// <summary>
2151  /// Loads a FreeImage multi-paged bitmap from a stream and returns the
2152  /// FreeImage memory stream used as temporary buffer.
2153  /// The bitmap can not be modified by calling
2154  /// <see cref="FreeImage.AppendPage(FIMULTIBITMAP,FIBITMAP)"/>,
2155  /// <see cref="FreeImage.InsertPage(FIMULTIBITMAP,Int32,FIBITMAP)"/>,
2156  /// <see cref="FreeImage.MovePage(FIMULTIBITMAP,Int32,Int32)"/> or
2157  /// <see cref="FreeImage.DeletePage(FIMULTIBITMAP,Int32)"/>.
2158  /// </summary>
2159  /// <param name="stream">The stream to read from.</param>
2160  /// <param name="format">Format of the image.</param>
2161  /// <param name="flags">Flags to enable or disable plugin-features.</param>
2162  /// <param name="memory">The temporary memory buffer used to load the bitmap.</param>
2163  /// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
2164  /// <exception cref="ArgumentNullException">
2165  /// <paramref name="stream"/> is null.</exception>
2166  /// <exception cref="ArgumentException">
2167  /// <paramref name="stream"/> can not read.</exception>
2168  public static FIMULTIBITMAP LoadMultiBitmapFromStream(
2169  Stream stream,
2170  FREE_IMAGE_FORMAT format,
2171  FREE_IMAGE_LOAD_FLAGS flags,
2172  out FIMEMORY memory)
2173  {
2174  if (stream == null)
2175  {
2176  throw new ArgumentNullException("stream");
2177  }
2178  if (!stream.CanRead)
2179  {
2180  throw new ArgumentException("stream");
2181  }
2182  const int blockSize = 1024;
2183  int bytesRead;
2184  byte[] buffer = new byte[blockSize];
2185 
2186  stream = stream.CanSeek ? stream : new StreamWrapper(stream, true);
2187  memory = OpenMemory(IntPtr.Zero, 0);
2188 
2189  do
2190  {
2191  bytesRead = stream.Read(buffer, 0, blockSize);
2192  WriteMemory(buffer, (uint)blockSize, (uint)1, memory);
2193  }
2194  while (bytesRead == blockSize);
2195 
2196  return LoadMultiBitmapFromMemory(format, memory, flags);
2197  }
2198 
2199  #endregion
2200 
2201  #region Filetype functions
2202 
2203  /// <summary>
2204  /// Orders FreeImage to analyze the bitmap signature.
2205  /// In case the stream is not seekable, the stream will have been used
2206  /// and must be recreated for loading.
2207  /// </summary>
2208  /// <param name="stream">Name of the stream to analyze.</param>
2209  /// <returns>Type of the bitmap.</returns>
2210  /// <exception cref="ArgumentNullException">
2211  /// <paramref name="stream"/> is null.</exception>
2212  /// <exception cref="ArgumentException">
2213  /// <paramref name="stream"/> can not read.</exception>
2214  public static FREE_IMAGE_FORMAT GetFileTypeFromStream(Stream stream)
2215  {
2216  if (stream == null)
2217  {
2218  throw new ArgumentNullException("stream");
2219  }
2220  if (!stream.CanRead)
2221  {
2222  throw new ArgumentException("stream is not capable of reading.");
2223  }
2224  // Wrap the stream if it cannot seek
2225  stream = (stream.CanSeek) ? stream : new StreamWrapper(stream, true);
2226  // Create a 'FreeImageIO' structure for the stream
2227  FreeImageIO io = FreeImageStreamIO.io;
2228  using (fi_handle handle = new fi_handle(stream))
2229  {
2230  return GetFileTypeFromHandle(ref io, handle, 0);
2231  }
2232  }
2233 
2234  #endregion
2235 
2236  #region Pixel access functions
2237 
2238  /// <summary>
2239  /// Retrieves an hBitmap for a FreeImage bitmap.
2240  /// Call FreeHbitmap(IntPtr) to free the handle.
2241  /// </summary>
2242  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2243  /// <param name="hdc">A reference device context.
2244  /// Use IntPtr.Zero if no reference is available.</param>
2245  /// <param name="unload">When true dib will be unloaded if the function succeeded.</param>
2246  /// <returns>The hBitmap for the FreeImage bitmap.</returns>
2247  /// <exception cref="ArgumentNullException">
2248  /// <paramref name="dib"/> is null.</exception>
2249  public static unsafe IntPtr GetHbitmap(FIBITMAP dib, IntPtr hdc, bool unload)
2250  {
2251  if (dib.IsNull)
2252  {
2253  throw new ArgumentNullException("dib");
2254  }
2255  IntPtr hBitmap = IntPtr.Zero;
2256  bool release = false;
2257  IntPtr ppvBits = IntPtr.Zero;
2258  // Check if we have destination
2259  if (release = (hdc == IntPtr.Zero))
2260  {
2261  // We don't so request dc
2262  hdc = GetDC(IntPtr.Zero);
2263  }
2264  if (hdc != IntPtr.Zero)
2265  {
2266  // Get pointer to the infoheader of the bitmap
2267  IntPtr info = GetInfo(dib);
2268  // Create a bitmap in the dc
2269  hBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0);
2270  if (hBitmap != IntPtr.Zero && ppvBits != IntPtr.Zero)
2271  {
2272  // Copy the data into the dc
2273  CopyMemory(ppvBits, GetBits(dib), (GetHeight(dib) * GetPitch(dib)));
2274  // Success: we unload the bitmap
2275  if (unload)
2276  {
2277  Unload(dib);
2278  }
2279  }
2280  // We have to release the dc
2281  if (release)
2282  {
2283  ReleaseDC(IntPtr.Zero, hdc);
2284  }
2285  }
2286  return hBitmap;
2287  }
2288 
2289  /// <summary>
2290  /// Returns an HBITMAP created by the <c>CreateDIBitmap()</c> function which in turn
2291  /// has always the same color depth as the reference DC, which may be provided
2292  /// through <paramref name="hdc"/>. The desktop DC will be used,
2293  /// if <c>IntPtr.Zero</c> DC is specified.
2294  /// Call <see cref="FreeImage.FreeHbitmap(IntPtr)"/> to free the handle.
2295  /// </summary>
2296  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2297  /// <param name="hdc">Handle to a device context.</param>
2298  /// <param name="unload">When true the structure will be unloaded on success.
2299  /// If the function failed and returned false, the bitmap was not unloaded.</param>
2300  /// <returns>If the function succeeds, the return value is a handle to the
2301  /// compatible bitmap. If the function fails, the return value is <see cref="IntPtr.Zero"/>.</returns>
2302  /// <exception cref="ArgumentNullException">
2303  /// <paramref name="dib"/> is null.</exception>
2304  public static IntPtr GetBitmapForDevice(FIBITMAP dib, IntPtr hdc, bool unload)
2305  {
2306  if (dib.IsNull)
2307  {
2308  throw new ArgumentNullException("dib");
2309  }
2310  IntPtr hbitmap = IntPtr.Zero;
2311  bool release = false;
2312  if (release = (hdc == IntPtr.Zero))
2313  {
2314  hdc = GetDC(IntPtr.Zero);
2315  }
2316  if (hdc != IntPtr.Zero)
2317  {
2318  hbitmap = CreateDIBitmap(
2319  hdc,
2320  GetInfoHeader(dib),
2321  CBM_INIT,
2322  GetBits(dib),
2323  GetInfo(dib),
2324  DIB_RGB_COLORS);
2325  if (unload)
2326  {
2327  Unload(dib);
2328  }
2329  if (release)
2330  {
2331  ReleaseDC(IntPtr.Zero, hdc);
2332  }
2333  }
2334  return hbitmap;
2335  }
2336 
2337  /// <summary>
2338  /// Creates a FreeImage DIB from a Device Context/Compatible Bitmap.
2339  /// </summary>
2340  /// <param name="hbitmap">Handle to the bitmap.</param>
2341  /// <param name="hdc">Handle to a device context.</param>
2342  /// <returns>Handle to a FreeImage bitmap.</returns>
2343  /// <exception cref="ArgumentNullException">
2344  /// <paramref name="hbitmap"/> is null.</exception>
2345  public unsafe static FIBITMAP CreateFromHbitmap(IntPtr hbitmap, IntPtr hdc)
2346  {
2347  if (hbitmap == IntPtr.Zero)
2348  {
2349  throw new ArgumentNullException("hbitmap");
2350  }
2351 
2352  FIBITMAP dib = new FIBITMAP();
2353  BITMAP bm;
2354  uint colors;
2355  bool release;
2356 
2357  if (GetObject(hbitmap, sizeof(BITMAP), (IntPtr)(&bm)) != 0)
2358  {
2359  dib = Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0, 0, 0);
2360  if (!dib.IsNull)
2361  {
2362  colors = GetColorsUsed(dib);
2363  if (release = (hdc == IntPtr.Zero))
2364  {
2365  hdc = GetDC(IntPtr.Zero);
2366  }
2367  if (GetDIBits(
2368  hdc,
2369  hbitmap,
2370  0,
2371  (uint)bm.bmHeight,
2372  GetBits(dib),
2373  GetInfo(dib),
2374  DIB_RGB_COLORS) != 0)
2375  {
2376  if (colors != 0)
2377  {
2378  BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)GetInfo(dib);
2379  bmih[0].biClrImportant = bmih[0].biClrUsed = colors;
2380  }
2381  }
2382  else
2383  {
2384  UnloadEx(ref dib);
2385  }
2386  if (release)
2387  {
2388  ReleaseDC(IntPtr.Zero, hdc);
2389  }
2390  }
2391  }
2392 
2393  return dib;
2394  }
2395 
2396  /// <summary>
2397  /// Frees a bitmap handle.
2398  /// </summary>
2399  /// <param name="hbitmap">Handle to a bitmap.</param>
2400  /// <returns>True on success, false on failure.</returns>
2401  public static bool FreeHbitmap(IntPtr hbitmap)
2402  {
2403  return DeleteObject(hbitmap);
2404  }
2405 
2406  #endregion
2407 
2408  #region Bitmap information functions
2409 
2410  /// <summary>
2411  /// Retrieves a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
2412  /// 'dots per meter'.
2413  /// </summary>
2414  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2415  /// <returns>The resolution in 'dots per inch'.</returns>
2416  /// <exception cref="ArgumentNullException">
2417  /// <paramref name="dib"/> is null.</exception>
2418  public static uint GetResolutionX(FIBITMAP dib)
2419  {
2420  if (dib.IsNull)
2421  {
2422  throw new ArgumentNullException("dib");
2423  }
2424  return (uint)(0.5d + 0.0254d * GetDotsPerMeterX(dib));
2425  }
2426 
2427  /// <summary>
2428  /// Retrieves a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
2429  /// 'dots per meter'.
2430  /// </summary>
2431  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2432  /// <returns>The resolution in 'dots per inch'.</returns>
2433  /// <exception cref="ArgumentNullException">
2434  /// <paramref name="dib"/> is null.</exception>
2435  public static uint GetResolutionY(FIBITMAP dib)
2436  {
2437  if (dib.IsNull)
2438  {
2439  throw new ArgumentNullException("dib");
2440  }
2441  return (uint)(0.5d + 0.0254d * GetDotsPerMeterY(dib));
2442  }
2443 
2444  /// <summary>
2445  /// Sets a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
2446  /// 'dots per meter'.
2447  /// </summary>
2448  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2449  /// <param name="res">The new resolution in 'dots per inch'.</param>
2450  /// <exception cref="ArgumentNullException">
2451  /// <paramref name="dib"/> is null.</exception>
2452  public static void SetResolutionX(FIBITMAP dib, uint res)
2453  {
2454  if (dib.IsNull)
2455  {
2456  throw new ArgumentNullException("dib");
2457  }
2458  SetDotsPerMeterX(dib, (uint)((double)res / 0.0254d + 0.5d));
2459  }
2460 
2461  /// <summary>
2462  /// Sets a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
2463  /// 'dots per meter'.
2464  /// </summary>
2465  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2466  /// <param name="res">The new resolution in 'dots per inch'.</param>
2467  /// <exception cref="ArgumentNullException">
2468  /// <paramref name="dib"/> is null.</exception>
2469  public static void SetResolutionY(FIBITMAP dib, uint res)
2470  {
2471  if (dib.IsNull)
2472  {
2473  throw new ArgumentNullException("dib");
2474  }
2475  SetDotsPerMeterY(dib, (uint)((double)res / 0.0254d + 0.5d));
2476  }
2477 
2478  /// <summary>
2479  /// Returns whether the image is a greyscale image or not.
2480  /// The function scans all colors in the bitmaps palette for entries where
2481  /// red, green and blue are not all the same (not a grey color).
2482  /// Supports 1-, 4- and 8-bit bitmaps.
2483  /// </summary>
2484  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2485  /// <returns>True if the image is a greyscale image, else false.</returns>
2486  /// <exception cref="ArgumentNullException">
2487  /// <paramref name="dib"/> is null.</exception>
2488  public static unsafe bool IsGreyscaleImage(FIBITMAP dib)
2489  {
2490  if (dib.IsNull)
2491  {
2492  throw new ArgumentNullException("dib");
2493  }
2494  bool result = true;
2495  uint bpp = GetBPP(dib);
2496  switch (bpp)
2497  {
2498  case 1:
2499  case 4:
2500  case 8:
2501  RGBQUAD* palette = (RGBQUAD*)GetPalette(dib);
2502  uint paletteLength = GetColorsUsed(dib);
2503  for (int i = 0; i < paletteLength; i++)
2504  {
2505  if (palette[i].rgbRed != palette[i].rgbGreen ||
2506  palette[i].rgbRed != palette[i].rgbBlue)
2507  {
2508  result = false;
2509  break;
2510  }
2511  }
2512  break;
2513  default:
2514  result = false;
2515  break;
2516  }
2517  return result;
2518  }
2519 
2520  /// <summary>
2521  /// Returns a structure that represents the palette of a FreeImage bitmap.
2522  /// </summary>
2523  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2524  /// <returns>A structure representing the bitmaps palette.</returns>
2525  /// <exception cref="ArgumentNullException">
2526  /// <paramref name="dib"/> is null.</exception>
2527  public static Palette GetPaletteEx(FIBITMAP dib)
2528  {
2529  return new Palette(dib);
2530  }
2531 
2532  /// <summary>
2533  /// Returns the <see cref="BITMAPINFOHEADER"/> structure of a FreeImage bitmap.
2534  /// The structure is a copy, so changes will have no effect on
2535  /// the bitmap itself.
2536  /// </summary>
2537  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2538  /// <returns><see cref="BITMAPINFOHEADER"/> structure of the bitmap.</returns>
2539  /// <exception cref="ArgumentNullException">
2540  /// <paramref name="dib"/> is null.</exception>
2541  public static unsafe BITMAPINFOHEADER GetInfoHeaderEx(FIBITMAP dib)
2542  {
2543  if (dib.IsNull)
2544  {
2545  throw new ArgumentNullException("dib");
2546  }
2547  return *(BITMAPINFOHEADER*)GetInfoHeader(dib);
2548  }
2549 
2550  /// <summary>
2551  /// Returns the <see cref="BITMAPINFO"/> structure of a FreeImage bitmap.
2552  /// The structure is a copy, so changes will have no effect on
2553  /// the bitmap itself.
2554  /// </summary>
2555  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2556  /// <returns><see cref="BITMAPINFO"/> structure of the bitmap.</returns>
2557  /// <exception cref="ArgumentNullException">
2558  /// <paramref name="dib"/> is null.</exception>
2559  public static BITMAPINFO GetInfoEx(FIBITMAP dib)
2560  {
2561  if (dib.IsNull)
2562  {
2563  throw new ArgumentNullException("dib");
2564  }
2565  BITMAPINFO result = new BITMAPINFO();
2566  result.bmiHeader = GetInfoHeaderEx(dib);
2567  IntPtr ptr = GetPalette(dib);
2568  if (ptr == IntPtr.Zero)
2569  {
2570  result.bmiColors = new RGBQUAD[0];
2571  }
2572  else
2573  {
2574  result.bmiColors = new MemoryArray<RGBQUAD>(ptr, (int)result.bmiHeader.biClrUsed).Data;
2575  }
2576  return result;
2577  }
2578 
2579  /// <summary>
2580  /// Returns the pixelformat of the bitmap.
2581  /// </summary>
2582  /// <param name="dib">Handle to a FreeImage bitmap.</param>
2583  /// <returns><see cref="System.Drawing.Imaging.PixelFormat"/> of the bitmap.</returns>
2584  /// <exception cref="ArgumentNullException">
2585  /// <paramref name="dib"/> is null.</exception>
2586  public static PixelFormat GetPixelFormat(FIBITMAP dib)
2587  {
2588  if (dib.IsNull)
2589  {
2590  throw new ArgumentNullException("dib");
2591  }
2592 
2593  PixelFormat result = PixelFormat.Undefined;
2594 
2595  if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
2596  {
2597  switch (GetBPP(dib))
2598  {
2599  case 1:
2600  result = PixelFormat.Format1bppIndexed;
2601  break;
2602  case 4:
2603  result = PixelFormat.Format4bppIndexed;
2604  break;
2605  case 8:
2606  result = PixelFormat.Format8bppIndexed;
2607  break;
2608  case 16:
2609  if ((GetBlueMask(dib) == FI16_565_BLUE_MASK) &&
2610  (GetGreenMask(dib) == FI16_565_GREEN_MASK) &&
2611  (GetRedMask(dib) == FI16_565_RED_MASK))
2612  {
2613  result = PixelFormat.Format16bppRgb565;
2614  }
2615  if ((GetBlueMask(dib) == FI16_555_BLUE_MASK) &&
2616  (GetGreenMask(dib) == FI16_555_GREEN_MASK) &&
2617  (GetRedMask(dib) == FI16_555_RED_MASK))
2618  {
2619  result = PixelFormat.Format16bppRgb555;
2620  }
2621  break;
2622  case 24:
2623  result = PixelFormat.Format24bppRgb;
2624  break;
2625  case 32:
2626  result = PixelFormat.Format32bppArgb;
2627  break;
2628  }
2629  }
2630  return result;
2631  }
2632 
2633  /// <summary>
2634  /// Retrieves all parameters needed to create a new FreeImage bitmap from
2635  /// the format of a .NET <see cref="System.Drawing.Image"/>.
2636  /// </summary>
2637  /// <param name="format">The <see cref="System.Drawing.Imaging.PixelFormat"/>
2638  /// of the .NET <see cref="System.Drawing.Image"/>.</param>
2639  /// <param name="type">Returns the type used for the new bitmap.</param>
2640  /// <param name="bpp">Returns the color depth for the new bitmap.</param>
2641  /// <param name="red_mask">Returns the red_mask for the new bitmap.</param>
2642  /// <param name="green_mask">Returns the green_mask for the new bitmap.</param>
2643  /// <param name="blue_mask">Returns the blue_mask for the new bitmap.</param>
2644  /// <returns>True in case a matching conversion exists; else false.
2645  /// </returns>
2646  public static bool GetFormatParameters(
2647  PixelFormat format,
2648  out FREE_IMAGE_TYPE type,
2649  out uint bpp,
2650  out uint red_mask,
2651  out uint green_mask,
2652  out uint blue_mask)
2653  {
2654  bool result = false;
2655  type = FREE_IMAGE_TYPE.FIT_UNKNOWN;
2656  bpp = 0;
2657  red_mask = 0;
2658  green_mask = 0;
2659  blue_mask = 0;
2660  switch (format)
2661  {
2662  case PixelFormat.Format1bppIndexed:
2663  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2664  bpp = 1;
2665  result = true;
2666  break;
2667  case PixelFormat.Format4bppIndexed:
2668  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2669  bpp = 4;
2670  result = true;
2671  break;
2672  case PixelFormat.Format8bppIndexed:
2673  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2674  bpp = 8;
2675  result = true;
2676  break;
2677  case PixelFormat.Format16bppRgb565:
2678  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2679  bpp = 16;
2680  red_mask = FI16_565_RED_MASK;
2681  green_mask = FI16_565_GREEN_MASK;
2682  blue_mask = FI16_565_BLUE_MASK;
2683  result = true;
2684  break;
2685  case PixelFormat.Format16bppRgb555:
2686  case PixelFormat.Format16bppArgb1555:
2687  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2688  bpp = 16;
2689  red_mask = FI16_555_RED_MASK;
2690  green_mask = FI16_555_GREEN_MASK;
2691  blue_mask = FI16_555_BLUE_MASK;
2692  result = true;
2693  break;
2694  case PixelFormat.Format24bppRgb:
2695  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2696  bpp = 24;
2697  red_mask = FI_RGBA_RED_MASK;
2698  green_mask = FI_RGBA_GREEN_MASK;
2699  blue_mask = FI_RGBA_BLUE_MASK;
2700  result = true;
2701  break;
2702  case PixelFormat.Format32bppRgb:
2703  case PixelFormat.Format32bppArgb:
2704  case PixelFormat.Format32bppPArgb:
2705  type = FREE_IMAGE_TYPE.FIT_BITMAP;
2706  bpp = 32;
2707  red_mask = FI_RGBA_RED_MASK;
2708  green_mask = FI_RGBA_GREEN_MASK;
2709  blue_mask = FI_RGBA_BLUE_MASK;
2710  result = true;
2711  break;
2712  case PixelFormat.Format16bppGrayScale:
2713  type = FREE_IMAGE_TYPE.FIT_UINT16;
2714  bpp = 16;
2715  result = true;
2716  break;
2717  case PixelFormat.Format48bppRgb:
2718  type = FREE_IMAGE_TYPE.FIT_RGB16;
2719  bpp = 48;
2720  result = true;
2721  break;
2722  case PixelFormat.Format64bppArgb:
2723  case PixelFormat.Format64bppPArgb:
2724  type = FREE_IMAGE_TYPE.FIT_RGBA16;
2725  bpp = 64;
2726  result = true;
2727  break;
2728  }
2729  return result;
2730  }
2731 
2732  /// <summary>
2733  /// Returns the <see cref="FREE_IMAGE_FORMAT"/> for the specified
2734  /// <see cref="ImageFormat"/>.
2735  /// </summary>
2736  /// <param name="imageFormat">The <see cref="ImageFormat"/>
2737  /// for which to return the corresponding <see cref="FREE_IMAGE_FORMAT"/>.</param>
2738  /// <returns>The <see cref="FREE_IMAGE_FORMAT"/> for the specified
2739  /// <see cref="ImageFormat"/></returns>
2740  public static FREE_IMAGE_FORMAT GetFormat(ImageFormat imageFormat)
2741  {
2742  if (imageFormat != null)
2743  {
2744  if (imageFormat.Equals(ImageFormat.Bmp))
2745  return FREE_IMAGE_FORMAT.FIF_BMP;
2746  if (imageFormat.Equals(ImageFormat.Gif))
2747  return FREE_IMAGE_FORMAT.FIF_GIF;
2748  if (imageFormat.Equals(ImageFormat.Icon))
2749  return FREE_IMAGE_FORMAT.FIF_ICO;
2750  if (imageFormat.Equals(ImageFormat.Jpeg))
2751  return FREE_IMAGE_FORMAT.FIF_JPEG;
2752  if (imageFormat.Equals(ImageFormat.Png))
2753  return FREE_IMAGE_FORMAT.FIF_PNG;
2754  if (imageFormat.Equals(ImageFormat.Tiff))
2755  return FREE_IMAGE_FORMAT.FIF_TIFF;
2756  }
2757  return FREE_IMAGE_FORMAT.FIF_UNKNOWN;
2758  }
2759 
2760  /// <summary>
2761  /// Retrieves all parameters needed to create a new FreeImage bitmap from
2762  /// raw bits <see cref="System.Drawing.Image"/>.
2763  /// </summary>
2764  /// <param name="type">The <see cref="FREE_IMAGE_TYPE"/>
2765  /// of the data in memory.</param>
2766  /// <param name="bpp">The color depth for the data.</param>
2767  /// <param name="red_mask">Returns the red_mask for the data.</param>
2768  /// <param name="green_mask">Returns the green_mask for the data.</param>
2769  /// <param name="blue_mask">Returns the blue_mask for the data.</param>
2770  /// <returns>True in case a matching conversion exists; else false.
2771  /// </returns>
2772  public static bool GetTypeParameters(
2773  FREE_IMAGE_TYPE type,
2774  int bpp,
2775  out uint red_mask,
2776  out uint green_mask,
2777  out uint blue_mask)
2778  {
2779  bool result = false;
2780  red_mask = 0;
2781  green_mask = 0;
2782  blue_mask = 0;
2783  switch (type)
2784  {
2785  case FREE_IMAGE_TYPE.FIT_BITMAP:
2786  switch (bpp)
2787  {
2788  case 1:
2789  case 4:
2790  case 8:
2791  result = true;
2792  break;
2793  case 16:
2794  result = true;
2795  red_mask = FI16_555_RED_MASK;
2796  green_mask = FI16_555_GREEN_MASK;
2797  blue_mask = FI16_555_BLUE_MASK;
2798  break;
2799  case 24:
2800  case 32:
2801  result = true;
2802  red_mask = FI_RGBA_RED_MASK;
2803  green_mask = FI_RGBA_GREEN_MASK;
2804  blue_mask = FI_RGBA_BLUE_MASK;
2805  break;
2806  }
2807  break;
2808  case FREE_IMAGE_TYPE.FIT_UNKNOWN:
2809  break;
2810  default:
2811  result = true;
2812  break;
2813  }
2814  return result;
2815  }
2816 
2817  /// <summary>
2818  /// Compares two FreeImage bitmaps.
2819  /// </summary>
2820  /// <param name="dib1">The first bitmap to compare.</param>
2821  /// <param name="dib2">The second bitmap to compare.</param>
2822  /// <param name="flags">Determines which components of the bitmaps will be compared.</param>
2823  /// <returns>True in case both bitmaps match the compare conditions, false otherwise.</returns>
2824  public static bool Compare(FIBITMAP dib1, FIBITMAP dib2, FREE_IMAGE_COMPARE_FLAGS flags)
2825  {
2826  // Check whether one bitmap is null
2827  if (dib1.IsNull ^ dib2.IsNull)
2828  {
2829  return false;
2830  }
2831  // Check whether both pointers are the same
2832  if (dib1 == dib2)
2833  {
2834  return true;
2835  }
2836  if (((flags & FREE_IMAGE_COMPARE_FLAGS.HEADER) > 0) && (!CompareHeader(dib1, dib2)))
2837  {
2838  return false;
2839  }
2840  if (((flags & FREE_IMAGE_COMPARE_FLAGS.PALETTE) > 0) && (!ComparePalette(dib1, dib2)))
2841  {
2842  return false;
2843  }
2844  if (((flags & FREE_IMAGE_COMPARE_FLAGS.DATA) > 0) && (!CompareData(dib1, dib2)))
2845  {
2846  return false;
2847  }
2848  if (((flags & FREE_IMAGE_COMPARE_FLAGS.METADATA) > 0) && (!CompareMetadata(dib1, dib2)))
2849  {
2850  return false;
2851  }
2852  return true;
2853  }
2854 
2855  private static unsafe bool CompareHeader(FIBITMAP dib1, FIBITMAP dib2)
2856  {
2857  IntPtr i1 = GetInfoHeader(dib1);
2858  IntPtr i2 = GetInfoHeader(dib2);
2859  return CompareMemory((void*)i1, (void*)i2, sizeof(BITMAPINFOHEADER));
2860  }
2861 
2862  private static unsafe bool ComparePalette(FIBITMAP dib1, FIBITMAP dib2)
2863  {
2864  IntPtr pal1 = GetPalette(dib1), pal2 = GetPalette(dib2);
2865  bool hasPalette1 = pal1 != IntPtr.Zero;
2866  bool hasPalette2 = pal2 != IntPtr.Zero;
2867  if (hasPalette1 ^ hasPalette2)
2868  {
2869  return false;
2870  }
2871  if (!hasPalette1)
2872  {
2873  return true;
2874  }
2875  uint colors = GetColorsUsed(dib1);
2876  if (colors != GetColorsUsed(dib2))
2877  {
2878  return false;
2879  }
2880  return CompareMemory((void*)pal1, (void*)pal2, sizeof(RGBQUAD) * colors);
2881  }
2882 
2883  private static unsafe bool CompareData(FIBITMAP dib1, FIBITMAP dib2)
2884  {
2885  uint width = GetWidth(dib1);
2886  if (width != GetWidth(dib2))
2887  {
2888  return false;
2889  }
2890  uint height = GetHeight(dib1);
2891  if (height != GetHeight(dib2))
2892  {
2893  return false;
2894  }
2895  uint bpp = GetBPP(dib1);
2896  if (bpp != GetBPP(dib2))
2897  {
2898  return false;
2899  }
2900  if (GetColorType(dib1) != GetColorType(dib2))
2901  {
2902  return false;
2903  }
2904  FREE_IMAGE_TYPE type = GetImageType(dib1);
2905  if (type != GetImageType(dib2))
2906  {
2907  return false;
2908  }
2909  if (GetRedMask(dib1) != GetRedMask(dib2))
2910  {
2911  return false;
2912  }
2913  if (GetGreenMask(dib1) != GetGreenMask(dib2))
2914  {
2915  return false;
2916  }
2917  if (GetBlueMask(dib1) != GetBlueMask(dib2))
2918  {
2919  return false;
2920  }
2921 
2922  byte* ptr1, ptr2;
2923  int fullBytes;
2924  int shift;
2925  uint line = GetLine(dib1);
2926 
2927  if (type == FREE_IMAGE_TYPE.FIT_BITMAP)
2928  {
2929  switch (bpp)
2930  {
2931  case 32:
2932  for (int i = 0; i < height; i++)
2933  {
2934  ptr1 = (byte*)GetScanLine(dib1, i);
2935  ptr2 = (byte*)GetScanLine(dib2, i);
2936  if (!CompareMemory(ptr1, ptr2, line))
2937  {
2938  return false;
2939  }
2940  }
2941  break;
2942  case 24:
2943  for (int i = 0; i < height; i++)
2944  {
2945  ptr1 = (byte*)GetScanLine(dib1, i);
2946  ptr2 = (byte*)GetScanLine(dib2, i);
2947  if (!CompareMemory(ptr1, ptr2, line))
2948  {
2949  return false;
2950  }
2951  }
2952  break;
2953  case 16:
2954  short* sPtr1, sPtr2;
2955  short mask = (short)(GetRedMask(dib1) | GetGreenMask(dib1) | GetBlueMask(dib1));
2956  if (mask == -1)
2957  {
2958  for (int i = 0; i < height; i++)
2959  {
2960  sPtr1 = (short*)GetScanLine(dib1, i);
2961  sPtr2 = (short*)GetScanLine(dib2, i);
2962  if (!CompareMemory(sPtr1, sPtr1, line))
2963  {
2964  return false;
2965  }
2966  }
2967  }
2968  else
2969  {
2970  for (int i = 0; i < height; i++)
2971  {
2972  sPtr1 = (short*)GetScanLine(dib1, i);
2973  sPtr2 = (short*)GetScanLine(dib2, i);
2974  for (int x = 0; x < width; x++)
2975  {
2976  if ((sPtr1[x] & mask) != (sPtr2[x] & mask))
2977  {
2978  return false;
2979  }
2980  }
2981  }
2982  }
2983  break;
2984  case 8:
2985  for (int i = 0; i < height; i++)
2986  {
2987  ptr1 = (byte*)GetScanLine(dib1, i);
2988  ptr2 = (byte*)GetScanLine(dib2, i);
2989  if (!CompareMemory(ptr1, ptr2, line))
2990  {
2991  return false;
2992  }
2993  }
2994  break;
2995  case 4:
2996  fullBytes = (int)width / 2;
2997  shift = (width % 2) == 0 ? 8 : 4;
2998  for (int i = 0; i < height; i++)
2999  {
3000  ptr1 = (byte*)GetScanLine(dib1, i);
3001  ptr2 = (byte*)GetScanLine(dib2, i);
3002  if (fullBytes != 0)
3003  {
3004  if (!CompareMemory(ptr1, ptr2, fullBytes))
3005  {
3006  return false;
3007  }
3008  ptr1 += fullBytes;
3009  ptr2 += fullBytes;
3010  }
3011  if (shift != 8)
3012  {
3013  if ((ptr1[0] >> shift) != (ptr2[0] >> shift))
3014  {
3015  return false;
3016  }
3017  }
3018  }
3019  break;
3020  case 1:
3021  fullBytes = (int)width / 8;
3022  shift = 8 - ((int)width % 8);
3023  for (int i = 0; i < height; i++)
3024  {
3025  ptr1 = (byte*)GetScanLine(dib1, i);
3026  ptr2 = (byte*)GetScanLine(dib2, i);
3027  if (fullBytes != 0)
3028  {
3029  if (!CompareMemory(ptr1, ptr2, fullBytes))
3030  {
3031  return false;
3032  }
3033  ptr1 += fullBytes;
3034  ptr2 += fullBytes;
3035  }
3036  if (shift != 8)
3037  {
3038  if ((ptr1[0] >> shift) != (ptr2[0] >> shift))
3039  {
3040  return false;
3041  }
3042  }
3043  }
3044  break;
3045  default:
3046  throw new NotSupportedException("Only 1, 4, 8, 16, 24 and 32 bpp bitmaps are supported.");
3047  }
3048  }
3049  else
3050  {
3051  for (int i = 0; i < height; i++)
3052  {
3053  ptr1 = (byte*)GetScanLine(dib1, i);
3054  ptr2 = (byte*)GetScanLine(dib2, i);
3055  if (!CompareMemory(ptr1, ptr2, line))
3056  {
3057  return false;
3058  }
3059  }
3060  }
3061  return true;
3062  }
3063 
3064  private static bool CompareMetadata(FIBITMAP dib1, FIBITMAP dib2)
3065  {
3066  MetadataTag tag1, tag2;
3067 
3068  foreach (FREE_IMAGE_MDMODEL metadataModel in FREE_IMAGE_MDMODELS)
3069  {
3070  if (GetMetadataCount(metadataModel, dib1) !=
3071  GetMetadataCount(metadataModel, dib2))
3072  {
3073  return false;
3074  }
3075  if (GetMetadataCount(metadataModel, dib1) == 0)
3076  {
3077  continue;
3078  }
3079 
3080  FIMETADATA mdHandle = FindFirstMetadata(metadataModel, dib1, out tag1);
3081  if (mdHandle.IsNull)
3082  {
3083  continue;
3084  }
3085  do
3086  {
3087  if ((!GetMetadata(metadataModel, dib2, tag1.Key, out tag2)) || (tag1 != tag2))
3088  {
3089  FindCloseMetadata(mdHandle);
3090  return false;
3091  }
3092  }
3093  while (FindNextMetadata(mdHandle, out tag1));
3094  FindCloseMetadata(mdHandle);
3095  }
3096 
3097  return true;
3098  }
3099 
3100  /// <summary>
3101  /// Returns the FreeImage bitmap's transparency table.
3102  /// The array is empty in case the bitmap has no transparency table.
3103  /// </summary>
3104  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3105  /// <returns>The FreeImage bitmap's transparency table.</returns>
3106  /// <exception cref="ArgumentNullException">
3107  /// <paramref name="dib"/> is null.</exception>
3108  public static unsafe byte[] GetTransparencyTableEx(FIBITMAP dib)
3109  {
3110  if (dib.IsNull)
3111  {
3112  throw new ArgumentNullException("dib");
3113  }
3114  uint count = GetTransparencyCount(dib);
3115  byte[] result = new byte[count];
3116  byte* ptr = (byte*)GetTransparencyTable(dib);
3117  fixed (byte* dst = result)
3118  {
3119  CopyMemory(dst, ptr, count);
3120  }
3121  return result;
3122  }
3123 
3124  /// <summary>
3125  /// Set the FreeImage bitmap's transparency table. Only affects palletised bitmaps.
3126  /// </summary>
3127  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3128  /// <param name="table">The FreeImage bitmap's new transparency table.</param>
3129  /// <exception cref="ArgumentNullException">
3130  /// <paramref name="dib"/> or <paramref name="table"/> is null.</exception>
3131  public static void SetTransparencyTable(FIBITMAP dib, byte[] table)
3132  {
3133  if (dib.IsNull)
3134  {
3135  throw new ArgumentNullException("dib");
3136  }
3137  if (table == null)
3138  {
3139  throw new ArgumentNullException("table");
3140  }
3141  SetTransparencyTable(dib, table, table.Length);
3142  }
3143 
3144  /// <summary>
3145  /// This function returns the number of unique colors actually used by the
3146  /// specified 1-, 4-, 8-, 16-, 24- or 32-bit image. This might be different from
3147  /// what function FreeImage_GetColorsUsed() returns, which actually returns the
3148  /// palette size for palletised images. Works for
3149  /// <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> type images only.
3150  /// </summary>
3151  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3152  /// <returns>Returns the number of unique colors used by the image specified or
3153  /// zero, if the image type cannot be handled.</returns>
3154  /// <exception cref="ArgumentNullException">
3155  /// <paramref name="dib"/> is null.</exception>
3156  public static unsafe int GetUniqueColors(FIBITMAP dib)
3157  {
3158  if (dib.IsNull)
3159  {
3160  throw new ArgumentNullException("dib");
3161  }
3162 
3163  int result = 0;
3164 
3165  if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
3166  {
3167  BitArray bitArray;
3168  int uniquePalEnts;
3169  int hashcode;
3170  byte[] lut;
3171  int width = (int)GetWidth(dib);
3172  int height = (int)GetHeight(dib);
3173 
3174  switch (GetBPP(dib))
3175  {
3176  case 1:
3177 
3178  result = 1;
3179  lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
3180  if (uniquePalEnts == 1)
3181  {
3182  break;
3183  }
3184 
3185  if ((*(byte*)GetScanLine(dib, 0) & 0x80) == 0)
3186  {
3187  for (int y = 0; y < height; y++)
3188  {
3189  byte* scanline = (byte*)GetScanLine(dib, y);
3190  int mask = 0x80;
3191  for (int x = 0; x < width; x++)
3192  {
3193  if ((scanline[x / 8] & mask) > 0)
3194  {
3195  return 2;
3196  }
3197  mask = (mask == 0x1) ? 0x80 : (mask >> 1);
3198  }
3199  }
3200  }
3201  else
3202  {
3203  for (int y = 0; y < height; y++)
3204  {
3205  byte* scanline = (byte*)GetScanLine(dib, y);
3206  int mask = 0x80;
3207  for (int x = 0; x < width; x++)
3208  {
3209  if ((scanline[x / 8] & mask) == 0)
3210  {
3211  return 2;
3212  }
3213  mask = (mask == 0x1) ? 0x80 : (mask >> 1);
3214  }
3215  }
3216  }
3217  break;
3218 
3219  case 4:
3220 
3221  bitArray = new BitArray(0x10);
3222  lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
3223  if (uniquePalEnts == 1)
3224  {
3225  result = 1;
3226  break;
3227  }
3228 
3229  for (int y = 0; (y < height) && (result < uniquePalEnts); y++)
3230  {
3231  byte* scanline = (byte*)GetScanLine(dib, y);
3232  bool top = true;
3233  for (int x = 0; (x < width) && (result < uniquePalEnts); x++)
3234  {
3235  if (top)
3236  {
3237  hashcode = lut[scanline[x / 2] >> 4];
3238  }
3239  else
3240  {
3241  hashcode = lut[scanline[x / 2] & 0xF];
3242  }
3243  top = !top;
3244  if (!bitArray[hashcode])
3245  {
3246  bitArray[hashcode] = true;
3247  result++;
3248  }
3249  }
3250  }
3251  break;
3252 
3253  case 8:
3254 
3255  bitArray = new BitArray(0x100);
3256  lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
3257  if (uniquePalEnts == 1)
3258  {
3259  result = 1;
3260  break;
3261  }
3262 
3263  for (int y = 0; (y < height) && (result < uniquePalEnts); y++)
3264  {
3265  byte* scanline = (byte*)GetScanLine(dib, y);
3266  for (int x = 0; (x < width) && (result < uniquePalEnts); x++)
3267  {
3268  hashcode = lut[scanline[x]];
3269  if (!bitArray[hashcode])
3270  {
3271  bitArray[hashcode] = true;
3272  result++;
3273  }
3274  }
3275  }
3276  break;
3277 
3278  case 16:
3279 
3280  bitArray = new BitArray(0x10000);
3281 
3282  for (int y = 0; y < height; y++)
3283  {
3284  short* scanline = (short*)GetScanLine(dib, y);
3285  for (int x = 0; x < width; x++, scanline++)
3286  {
3287  hashcode = *scanline;
3288  if (!bitArray[hashcode])
3289  {
3290  bitArray[hashcode] = true;
3291  result++;
3292  }
3293  }
3294  }
3295  break;
3296 
3297  case 24:
3298 
3299  bitArray = new BitArray(0x1000000);
3300 
3301  for (int y = 0; y < height; y++)
3302  {
3303  byte* scanline = (byte*)GetScanLine(dib, y);
3304  for (int x = 0; x < width; x++, scanline += 3)
3305  {
3306  hashcode = *((int*)scanline) & 0x00FFFFFF;
3307  if (!bitArray[hashcode])
3308  {
3309  bitArray[hashcode] = true;
3310  result++;
3311  }
3312  }
3313  }
3314  break;
3315 
3316  case 32:
3317 
3318  bitArray = new BitArray(0x1000000);
3319 
3320  for (int y = 0; y < height; y++)
3321  {
3322  int* scanline = (int*)GetScanLine(dib, y);
3323  for (int x = 0; x < width; x++, scanline++)
3324  {
3325  hashcode = *scanline & 0x00FFFFFF;
3326  if (!bitArray[hashcode])
3327  {
3328  bitArray[hashcode] = true;
3329  result++;
3330  }
3331  }
3332  }
3333  break;
3334  }
3335  }
3336  return result;
3337  }
3338 
3339  /// <summary>
3340  /// Verifies whether the FreeImage bitmap is 16bit 555.
3341  /// </summary>
3342  /// <param name="dib">The FreeImage bitmap to verify.</param>
3343  /// <returns><b>true</b> if the bitmap is RGB16-555; otherwise <b>false</b>.</returns>
3344  public static bool IsRGB555(FIBITMAP dib)
3345  {
3346  return ((GetRedMask(dib) == FI16_555_RED_MASK) &&
3347  (GetGreenMask(dib) == FI16_555_GREEN_MASK) &&
3348  (GetBlueMask(dib) == FI16_555_BLUE_MASK));
3349  }
3350 
3351  /// <summary>
3352  /// Verifies whether the FreeImage bitmap is 16bit 565.
3353  /// </summary>
3354  /// <param name="dib">The FreeImage bitmap to verify.</param>
3355  /// <returns><b>true</b> if the bitmap is RGB16-565; otherwise <b>false</b>.</returns>
3356  public static bool IsRGB565(FIBITMAP dib)
3357  {
3358  return ((GetRedMask(dib) == FI16_565_RED_MASK) &&
3359  (GetGreenMask(dib) == FI16_565_GREEN_MASK) &&
3360  (GetBlueMask(dib) == FI16_565_BLUE_MASK));
3361  }
3362 
3363  #endregion
3364 
3365  #region ICC profile functions
3366 
3367  /// <summary>
3368  /// Creates a new ICC-Profile for a FreeImage bitmap.
3369  /// </summary>
3370  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3371  /// <param name="data">The data of the new ICC-Profile.</param>
3372  /// <returns>The new ICC-Profile of the bitmap.</returns>
3373  /// <exception cref="ArgumentNullException">
3374  /// <paramref name="dib"/> is null.</exception>
3375  public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data)
3376  {
3377  return new FIICCPROFILE(dib, data);
3378  }
3379 
3380  /// <summary>
3381  /// Creates a new ICC-Profile for a FreeImage bitmap.
3382  /// </summary>
3383  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3384  /// <param name="data">The data of the new ICC-Profile.</param>
3385  /// <param name="size">The number of bytes of <paramref name="data"/> to use.</param>
3386  /// <returns>The new ICC-Profile of the FreeImage bitmap.</returns>
3387  /// <exception cref="ArgumentNullException">
3388  /// <paramref name="dib"/> is null.</exception>
3389  public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data, int size)
3390  {
3391  return new FIICCPROFILE(dib, data, size);
3392  }
3393 
3394  #endregion
3395 
3396  #region Conversion functions
3397 
3398  /// <summary>
3399  /// Converts a FreeImage bitmap from one color depth to another.
3400  /// If the conversion fails the original FreeImage bitmap is returned.
3401  /// </summary>
3402  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3403  /// <param name="conversion">The desired output format.</param>
3404  /// <returns>Handle to a FreeImage bitmap.</returns>
3405  /// <exception cref="ArgumentNullException">
3406  /// <paramref name="dib"/> is null.</exception>
3407  public static FIBITMAP ConvertColorDepth(
3408  FIBITMAP dib,
3409  FREE_IMAGE_COLOR_DEPTH conversion)
3410  {
3411  return ConvertColorDepth(
3412  dib,
3413  conversion,
3414  128,
3415  FREE_IMAGE_DITHER.FID_FS,
3416  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3417  false);
3418  }
3419 
3420  /// <summary>
3421  /// Converts a FreeImage bitmap from one color depth to another.
3422  /// If the conversion fails the original FreeImage bitmap is returned.
3423  /// </summary>
3424  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3425  /// <param name="conversion">The desired output format.</param>
3426  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
3427  /// <returns>Handle to a FreeImage bitmap.</returns>
3428  /// <exception cref="ArgumentNullException">
3429  /// <paramref name="dib"/> is null.</exception>
3430  public static FIBITMAP ConvertColorDepth(
3431  FIBITMAP dib,
3432  FREE_IMAGE_COLOR_DEPTH conversion,
3433  bool unloadSource)
3434  {
3435  return ConvertColorDepth(
3436  dib,
3437  conversion,
3438  128,
3439  FREE_IMAGE_DITHER.FID_FS,
3440  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3441  unloadSource);
3442  }
3443 
3444  /// <summary>
3445  /// Converts a FreeImage bitmap from one color depth to another.
3446  /// If the conversion fails the original FreeImage bitmap is returned.
3447  /// </summary>
3448  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3449  /// <param name="conversion">The desired output format.</param>
3450  /// <param name="threshold">Threshold value when converting with
3451  /// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
3452  /// <returns>Handle to a FreeImage bitmap.</returns>
3453  /// <exception cref="ArgumentNullException">
3454  /// <paramref name="dib"/> is null.</exception>
3455  public static FIBITMAP ConvertColorDepth(
3456  FIBITMAP dib,
3457  FREE_IMAGE_COLOR_DEPTH conversion,
3458  byte threshold)
3459  {
3460  return ConvertColorDepth(
3461  dib,
3462  conversion,
3463  threshold,
3464  FREE_IMAGE_DITHER.FID_FS,
3465  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3466  false);
3467  }
3468 
3469  /// <summary>
3470  /// Converts a FreeImage bitmap from one color depth to another.
3471  /// If the conversion fails the original FreeImage bitmap is returned.
3472  /// </summary>
3473  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3474  /// <param name="conversion">The desired output format.</param>
3475  /// <param name="ditherMethod">Dither algorithm when converting
3476  /// with <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
3477  /// <returns>Handle to a FreeImage bitmap.</returns>
3478  /// <exception cref="ArgumentNullException">
3479  /// <paramref name="dib"/> is null.</exception>
3480  public static FIBITMAP ConvertColorDepth(
3481  FIBITMAP dib,
3482  FREE_IMAGE_COLOR_DEPTH conversion,
3483  FREE_IMAGE_DITHER ditherMethod)
3484  {
3485  return ConvertColorDepth(
3486  dib,
3487  conversion,
3488  128,
3489  ditherMethod,
3490  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3491  false);
3492  }
3493 
3494 
3495  /// <summary>
3496  /// Converts a FreeImage bitmap from one color depth to another.
3497  /// If the conversion fails the original FreeImage bitmap is returned.
3498  /// </summary>
3499  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3500  /// <param name="conversion">The desired output format.</param>
3501  /// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
3502  /// <returns>Handle to a FreeImage bitmap.</returns>
3503  /// <exception cref="ArgumentNullException">
3504  /// <paramref name="dib"/> is null.</exception>
3505  public static FIBITMAP ConvertColorDepth(
3506  FIBITMAP dib,
3507  FREE_IMAGE_COLOR_DEPTH conversion,
3508  FREE_IMAGE_QUANTIZE quantizationMethod)
3509  {
3510  return ConvertColorDepth(
3511  dib,
3512  conversion,
3513  128,
3514  FREE_IMAGE_DITHER.FID_FS,
3515  quantizationMethod,
3516  false);
3517  }
3518 
3519  /// <summary>
3520  /// Converts a FreeImage bitmap from one color depth to another.
3521  /// If the conversion fails the original FreeImage bitmap is returned.
3522  /// </summary>
3523  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3524  /// <param name="conversion">The desired output format.</param>
3525  /// <param name="threshold">Threshold value when converting with
3526  /// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
3527  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
3528  /// <returns>Handle to a FreeImage bitmap.</returns>
3529  /// <exception cref="ArgumentNullException">
3530  /// <paramref name="dib"/> is null.</exception>
3531  public static FIBITMAP ConvertColorDepth(
3532  FIBITMAP dib,
3533  FREE_IMAGE_COLOR_DEPTH conversion,
3534  byte threshold,
3535  bool unloadSource)
3536  {
3537  return ConvertColorDepth(
3538  dib,
3539  conversion,
3540  threshold,
3541  FREE_IMAGE_DITHER.FID_FS,
3542  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3543  unloadSource);
3544  }
3545 
3546  /// <summary>
3547  /// Converts a FreeImage bitmap from one color depth to another.
3548  /// If the conversion fails the original FreeImage bitmap is returned.
3549  /// </summary>
3550  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3551  /// <param name="conversion">The desired output format.</param>
3552  /// <param name="ditherMethod">Dither algorithm when converting with
3553  /// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
3554  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
3555  /// <returns>Handle to a FreeImage bitmap.</returns>
3556  /// <exception cref="ArgumentNullException">
3557  /// <paramref name="dib"/> is null.</exception>
3558  public static FIBITMAP ConvertColorDepth(
3559  FIBITMAP dib,
3560  FREE_IMAGE_COLOR_DEPTH conversion,
3561  FREE_IMAGE_DITHER ditherMethod,
3562  bool unloadSource)
3563  {
3564  return ConvertColorDepth(
3565  dib,
3566  conversion,
3567  128,
3568  ditherMethod,
3569  FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
3570  unloadSource);
3571  }
3572 
3573 
3574  /// <summary>
3575  /// Converts a FreeImage bitmap from one color depth to another.
3576  /// If the conversion fails the original FreeImage bitmap is returned.
3577  /// </summary>
3578  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3579  /// <param name="conversion">The desired output format.</param>
3580  /// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
3581  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
3582  /// <returns>Handle to a FreeImage bitmap.</returns>
3583  /// <exception cref="ArgumentNullException">
3584  /// <paramref name="dib"/> is null.</exception>
3585  public static FIBITMAP ConvertColorDepth(
3586  FIBITMAP dib,
3587  FREE_IMAGE_COLOR_DEPTH conversion,
3588  FREE_IMAGE_QUANTIZE quantizationMethod,
3589  bool unloadSource)
3590  {
3591  return ConvertColorDepth(
3592  dib,
3593  conversion,
3594  128,
3595  FREE_IMAGE_DITHER.FID_FS,
3596  quantizationMethod,
3597  unloadSource);
3598  }
3599 
3600  /// <summary>
3601  /// Converts a FreeImage bitmap from one color depth to another.
3602  /// If the conversion fails the original FreeImage bitmap is returned.
3603  /// </summary>
3604  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3605  /// <param name="conversion">The desired output format.</param>
3606  /// <param name="threshold">Threshold value when converting with
3607  /// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
3608  /// <param name="ditherMethod">Dither algorithm when converting with
3609  /// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
3610  /// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
3611  /// <param name="unloadSource">When true the structure will be unloaded on success.</param>
3612  /// <returns>Handle to a FreeImage bitmap.</returns>
3613  /// <exception cref="ArgumentNullException">
3614  /// <paramref name="dib"/> is null.</exception>
3615  internal static FIBITMAP ConvertColorDepth(
3616  FIBITMAP dib,
3617  FREE_IMAGE_COLOR_DEPTH conversion,
3618  byte threshold,
3619  FREE_IMAGE_DITHER ditherMethod,
3620  FREE_IMAGE_QUANTIZE quantizationMethod,
3621  bool unloadSource)
3622  {
3623  if (dib.IsNull)
3624  {
3625  throw new ArgumentNullException("dib");
3626  }
3627 
3628  FIBITMAP result = new FIBITMAP();
3629  FIBITMAP dibTemp = new FIBITMAP();
3630  uint bpp = GetBPP(dib);
3631  bool reorderPalette = ((conversion & FREE_IMAGE_COLOR_DEPTH.FICD_REORDER_PALETTE) > 0);
3632  bool forceGreyscale = ((conversion & FREE_IMAGE_COLOR_DEPTH.FICD_FORCE_GREYSCALE) > 0);
3633 
3634  if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
3635  {
3636  switch (conversion & (FREE_IMAGE_COLOR_DEPTH)0xFF)
3637  {
3638  case FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD:
3639 
3640  if (bpp != 1)
3641  {
3642  if (forceGreyscale)
3643  {
3644  result = Threshold(dib, threshold);
3645  }
3646  else
3647  {
3648  dibTemp = ConvertTo24Bits(dib);
3649  result = ColorQuantizeEx(dibTemp, quantizationMethod, 2, null, 1);
3650  Unload(dibTemp);
3651  }
3652  }
3653  else
3654  {
3655  bool isGreyscale = IsGreyscaleImage(dib);
3656  if ((forceGreyscale && (!isGreyscale)) ||
3657  (reorderPalette && isGreyscale))
3658  {
3659  result = Threshold(dib, threshold);
3660  }
3661  }
3662  break;
3663 
3664  case FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER:
3665 
3666  if (bpp != 1)
3667  {
3668  if (forceGreyscale)
3669  {
3670  result = Dither(dib, ditherMethod);
3671  }
3672  else
3673  {
3674  dibTemp = ConvertTo24Bits(dib);
3675  result = ColorQuantizeEx(dibTemp, quantizationMethod, 2, null, 1);
3676  Unload(dibTemp);
3677  }
3678  }
3679  else
3680  {
3681  bool isGreyscale = IsGreyscaleImage(dib);
3682  if ((forceGreyscale && (!isGreyscale)) ||
3683  (reorderPalette && isGreyscale))
3684  {
3685  result = Dither(dib, ditherMethod);
3686  }
3687  }
3688  break;
3689 
3690  case FREE_IMAGE_COLOR_DEPTH.FICD_04_BPP:
3691 
3692  if (bpp != 4)
3693  {
3694  // Special case when 1bpp and FIC_PALETTE
3695  if (forceGreyscale ||
3696  ((bpp == 1) && (GetColorType(dib) == FREE_IMAGE_COLOR_TYPE.FIC_PALETTE)))
3697  {
3698  dibTemp = ConvertToGreyscale(dib);
3699  result = ConvertTo4Bits(dibTemp);
3700  Unload(dibTemp);
3701  }
3702  else
3703  {
3704  dibTemp = ConvertTo24Bits(dib);
3705  result = ColorQuantizeEx(dibTemp, quantizationMethod, 16, null, 4);
3706  Unload(dibTemp);
3707  }
3708  }
3709  else
3710  {
3711  bool isGreyscale = IsGreyscaleImage(dib);
3712  if ((forceGreyscale && (!isGreyscale)) ||
3713  (reorderPalette && isGreyscale))
3714  {
3715  dibTemp = ConvertToGreyscale(dib);
3716  result = ConvertTo4Bits(dibTemp);
3717  Unload(dibTemp);
3718  }
3719  }
3720 
3721  break;
3722 
3723  case FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP:
3724 
3725  if (bpp != 8)
3726  {
3727  if (forceGreyscale)
3728  {
3729  result = ConvertToGreyscale(dib);
3730  }
3731  else
3732  {
3733  dibTemp = ConvertTo24Bits(dib);
3734  result = ColorQuantize(dibTemp, quantizationMethod);
3735  Unload(dibTemp);
3736  }
3737  }
3738  else
3739  {
3740  bool isGreyscale = IsGreyscaleImage(dib);
3741  if ((forceGreyscale && (!isGreyscale)) || (reorderPalette && isGreyscale))
3742  {
3743  result = ConvertToGreyscale(dib);
3744  }
3745  }
3746  break;
3747 
3748  case FREE_IMAGE_COLOR_DEPTH.FICD_16_BPP_555:
3749 
3750  if (forceGreyscale)
3751  {
3752  dibTemp = ConvertToGreyscale(dib);
3753  result = ConvertTo16Bits555(dibTemp);
3754  Unload(dibTemp);
3755  }
3756  else if (bpp != 16 || GetRedMask(dib) != FI16_555_RED_MASK || GetGreenMask(dib) != FI16_555_GREEN_MASK || GetBlueMask(dib) != FI16_555_BLUE_MASK)
3757  {
3758  result = ConvertTo16Bits555(dib);
3759  }
3760  break;
3761 
3762  case FREE_IMAGE_COLOR_DEPTH.FICD_16_BPP:
3763 
3764  if (forceGreyscale)
3765  {
3766  dibTemp = ConvertToGreyscale(dib);
3767  result = ConvertTo16Bits565(dibTemp);
3768  Unload(dibTemp);
3769  }
3770  else if (bpp != 16 || GetRedMask(dib) != FI16_565_RED_MASK || GetGreenMask(dib) != FI16_565_GREEN_MASK || GetBlueMask(dib) != FI16_565_BLUE_MASK)
3771  {
3772  result = ConvertTo16Bits565(dib);
3773  }
3774  break;
3775 
3776  case FREE_IMAGE_COLOR_DEPTH.FICD_24_BPP:
3777 
3778  if (forceGreyscale)
3779  {
3780  dibTemp = ConvertToGreyscale(dib);
3781  result = ConvertTo24Bits(dibTemp);
3782  Unload(dibTemp);
3783  }
3784  else if (bpp != 24)
3785  {
3786  result = ConvertTo24Bits(dib);
3787  }
3788  break;
3789 
3790  case FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP:
3791 
3792  if (forceGreyscale)
3793  {
3794  dibTemp = ConvertToGreyscale(dib);
3795  result = ConvertTo32Bits(dibTemp);
3796  Unload(dibTemp);
3797  }
3798  else if (bpp != 32)
3799  {
3800  result = ConvertTo32Bits(dib);
3801  }
3802  break;
3803  }
3804  }
3805 
3806  if (result.IsNull)
3807  {
3808  return dib;
3809  }
3810  if (unloadSource)
3811  {
3812  Unload(dib);
3813  }
3814 
3815  return result;
3816  }
3817 
3818  /// <summary>
3819  /// ColorQuantizeEx is an extension to the <see cref="ColorQuantize(FIBITMAP, FREE_IMAGE_QUANTIZE)"/>
3820  /// method that provides additional options used to quantize a 24-bit image to any
3821  /// number of colors (up to 256), as well as quantize a 24-bit image using a
3822  /// provided palette.
3823  /// </summary>
3824  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3825  /// <param name="quantize">Specifies the color reduction algorithm to be used.</param>
3826  /// <param name="PaletteSize">Size of the desired output palette.</param>
3827  /// <param name="ReservePalette">The provided palette.</param>
3828  /// <param name="minColorDepth"><b>true</b> to create a bitmap with the smallest possible
3829  /// color depth for the specified <paramref name="PaletteSize"/>.</param>
3830  /// <returns>Handle to a FreeImage bitmap.</returns>
3831  public static FIBITMAP ColorQuantizeEx(FIBITMAP dib, FREE_IMAGE_QUANTIZE quantize, int PaletteSize, RGBQUAD[] ReservePalette, bool minColorDepth)
3832  {
3833  FIBITMAP result;
3834  if (minColorDepth)
3835  {
3836  int bpp;
3837  if (PaletteSize >= 256)
3838  bpp = 8;
3839  else if (PaletteSize > 2)
3840  bpp = 4;
3841  else
3842  bpp = 1;
3843  result = ColorQuantizeEx(dib, quantize, PaletteSize, ReservePalette, bpp);
3844  }
3845  else
3846  {
3847  result = ColorQuantizeEx(dib, quantize, PaletteSize, ReservePalette, 8);
3848  }
3849  return result;
3850  }
3851 
3852  /// <summary>
3853  /// ColorQuantizeEx is an extension to the <see cref="ColorQuantize(FIBITMAP, FREE_IMAGE_QUANTIZE)"/>
3854  /// method that provides additional options used to quantize a 24-bit image to any
3855  /// number of colors (up to 256), as well as quantize a 24-bit image using a
3856  /// partial or full provided palette.
3857  /// </summary>
3858  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3859  /// <param name="quantize">Specifies the color reduction algorithm to be used.</param>
3860  /// <param name="PaletteSize">Size of the desired output palette.</param>
3861  /// <param name="ReservePalette">The provided palette.</param>
3862  /// <param name="bpp">The desired color depth of the created image.</param>
3863  /// <returns>Handle to a FreeImage bitmap.</returns>
3864  public static FIBITMAP ColorQuantizeEx(FIBITMAP dib, FREE_IMAGE_QUANTIZE quantize, int PaletteSize, RGBQUAD[] ReservePalette, int bpp)
3865  {
3866  unsafe
3867  {
3868  FIBITMAP result = FIBITMAP.Zero;
3869  FIBITMAP temp = FIBITMAP.Zero;
3870  int reservedSize = (ReservePalette == null) ? 0 : ReservePalette.Length;
3871 
3872  if (bpp == 8)
3873  {
3874  result = ColorQuantizeEx(dib, quantize, PaletteSize, reservedSize, ReservePalette);
3875  }
3876  else if (bpp == 4)
3877  {
3878  temp = ColorQuantizeEx(dib, quantize, Math.Min(16, PaletteSize), reservedSize, ReservePalette);
3879  if (!temp.IsNull)
3880  {
3881  result = Allocate((int)GetWidth(temp), (int)GetHeight(temp), 4, 0, 0, 0);
3882  CloneMetadata(result, temp);
3883  CopyMemory(GetPalette(result), GetPalette(temp), sizeof(RGBQUAD) * 16);
3884 
3885  for (int y = (int)GetHeight(temp) - 1; y >= 0; y--)
3886  {
3887  Scanline<byte> srcScanline = new Scanline<byte>(temp, y);
3888  Scanline<FI4BIT> dstScanline = new Scanline<FI4BIT>(result, y);
3889 
3890  for (int x = (int)GetWidth(temp) - 1; x >= 0; x--)
3891  {
3892  dstScanline[x] = srcScanline[x];
3893  }
3894  }
3895  }
3896  }
3897  else if (bpp == 1)
3898  {
3899  temp = ColorQuantizeEx(dib, quantize, 2, reservedSize, ReservePalette);
3900  if (!temp.IsNull)
3901  {
3902  result = Allocate((int)GetWidth(temp), (int)GetHeight(temp), 1, 0, 0, 0);
3903  CloneMetadata(result, temp);
3904  CopyMemory(GetPalette(result), GetPalette(temp), sizeof(RGBQUAD) * 2);
3905 
3906  for (int y = (int)GetHeight(temp) - 1; y >= 0; y--)
3907  {
3908  Scanline<byte> srcScanline = new Scanline<byte>(temp, y);
3909  Scanline<FI1BIT> dstScanline = new Scanline<FI1BIT>(result, y);
3910 
3911  for (int x = (int)GetWidth(temp) - 1; x >= 0; x--)
3912  {
3913  dstScanline[x] = srcScanline[x];
3914  }
3915  }
3916  }
3917  }
3918 
3919  UnloadEx(ref temp);
3920  return result;
3921  }
3922  }
3923 
3924  #endregion
3925 
3926  #region Metadata
3927 
3928  /// <summary>
3929  /// Copies metadata from one FreeImage bitmap to another.
3930  /// </summary>
3931  /// <param name="src">Source FreeImage bitmap containing the metadata.</param>
3932  /// <param name="dst">FreeImage bitmap to copy the metadata to.</param>
3933  /// <param name="flags">Flags to switch different copy modes.</param>
3934  /// <returns>Returns -1 on failure else the number of copied tags.</returns>
3935  /// <exception cref="ArgumentNullException">
3936  /// <paramref name="src"/> or <paramref name="dst"/> is null.</exception>
3937  public static int CloneMetadataEx(FIBITMAP src, FIBITMAP dst, FREE_IMAGE_METADATA_COPY flags)
3938  {
3939  if (src.IsNull)
3940  {
3941  throw new ArgumentNullException("src");
3942  }
3943  if (dst.IsNull)
3944  {
3945  throw new ArgumentNullException("dst");
3946  }
3947 
3948  FITAG tag = new FITAG(), tag2 = new FITAG();
3949  int copied = 0;
3950 
3951  // Clear all existing metadata
3952  if ((flags & FREE_IMAGE_METADATA_COPY.CLEAR_EXISTING) > 0)
3953  {
3954  foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
3955  {
3956  if (!SetMetadata(model, dst, null, tag))
3957  {
3958  return -1;
3959  }
3960  }
3961  }
3962 
3963  bool keep = !((flags & FREE_IMAGE_METADATA_COPY.REPLACE_EXISTING) > 0);
3964 
3965  foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
3966  {
3967  FIMETADATA mData = FindFirstMetadata(model, src, out tag);
3968  if (mData.IsNull) continue;
3969  do
3970  {
3971  string key = GetTagKey(tag);
3972  if (!(keep && GetMetadata(model, dst, key, out tag2)))
3973  {
3974  if (SetMetadata(model, dst, key, tag))
3975  {
3976  copied++;
3977  }
3978  }
3979  }
3980  while (FindNextMetadata(mData, out tag));
3981  FindCloseMetadata(mData);
3982  }
3983 
3984  return copied;
3985  }
3986 
3987  /// <summary>
3988  /// Returns the comment of a JPEG, PNG or GIF image.
3989  /// </summary>
3990  /// <param name="dib">Handle to a FreeImage bitmap.</param>
3991  /// <returns>Comment of the FreeImage bitmp, or null in case no comment exists.</returns>
3992  /// <exception cref="ArgumentNullException">
3993  /// <paramref name="dib"/> is null.</exception>
3994  public static string GetImageComment(FIBITMAP dib)
3995  {
3996  string result = null;
3997  if (dib.IsNull)
3998  {
3999  throw new ArgumentNullException("dib");
4000  }
4001  FITAG tag;
4002  if (GetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", out tag))
4003  {
4004  MetadataTag metadataTag = new MetadataTag(tag, FREE_IMAGE_MDMODEL.FIMD_COMMENTS);
4005  result = metadataTag.Value as string;
4006  }
4007  return result;
4008  }
4009 
4010  /// <summary>
4011  /// Sets the comment of a JPEG, PNG or GIF image.
4012  /// </summary>
4013  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4014  /// <param name="comment">New comment of the FreeImage bitmap.
4015  /// Use null to remove the comment.</param>
4016  /// <returns>Returns true on success, false on failure.</returns>
4017  /// <exception cref="ArgumentNullException">
4018  /// <paramref name="dib"/> is null.</exception>
4019  public static bool SetImageComment(FIBITMAP dib, string comment)
4020  {
4021  if (dib.IsNull)
4022  {
4023  throw new ArgumentNullException("dib");
4024  }
4025  bool result;
4026  if (comment != null)
4027  {
4028  FITAG tag = CreateTag();
4029  MetadataTag metadataTag = new MetadataTag(tag, FREE_IMAGE_MDMODEL.FIMD_COMMENTS);
4030  metadataTag.Value = comment;
4031  result = SetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", tag);
4032  DeleteTag(tag);
4033  }
4034  else
4035  {
4036  result = SetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", FITAG.Zero);
4037  }
4038  return result;
4039  }
4040 
4041  /// <summary>
4042  /// Retrieve a metadata attached to a FreeImage bitmap.
4043  /// </summary>
4044  /// <param name="model">The metadata model to look for.</param>
4045  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4046  /// <param name="key">The metadata field name.</param>
4047  /// <param name="tag">A <see cref="MetadataTag"/> structure returned by the function.</param>
4048  /// <returns>Returns true on success, false on failure.</returns>
4049  /// <exception cref="ArgumentNullException">
4050  /// <paramref name="dib"/> is null.</exception>
4051  public static bool GetMetadata(
4052  FREE_IMAGE_MDMODEL model,
4053  FIBITMAP dib,
4054  string key,
4055  out MetadataTag tag)
4056  {
4057  if (dib.IsNull)
4058  {
4059  throw new ArgumentNullException("dib");
4060  }
4061 
4062  FITAG _tag;
4063  bool result;
4064  if (GetMetadata(model, dib, key, out _tag))
4065  {
4066  tag = new MetadataTag(_tag, model);
4067  result = true;
4068  }
4069  else
4070  {
4071  tag = null;
4072  result = false;
4073  }
4074  return result;
4075  }
4076 
4077  /// <summary>
4078  /// Attach a new metadata tag to a FreeImage bitmap.
4079  /// </summary>
4080  /// <param name="model">The metadata model used to store the tag.</param>
4081  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4082  /// <param name="key">The tag field name.</param>
4083  /// <param name="tag">The <see cref="MetadataTag"/> to be attached.</param>
4084  /// <returns>Returns true on success, false on failure.</returns>
4085  /// <exception cref="ArgumentNullException">
4086  /// <paramref name="dib"/> is null.</exception>
4087  public static bool SetMetadata(
4088  FREE_IMAGE_MDMODEL model,
4089  FIBITMAP dib,
4090  string key,
4091  MetadataTag tag)
4092  {
4093  if (dib.IsNull)
4094  {
4095  throw new ArgumentNullException("dib");
4096  }
4097  return SetMetadata(model, dib, key, tag.tag);
4098  }
4099 
4100  /// <summary>
4101  /// Provides information about the first instance of a tag that matches the metadata model.
4102  /// </summary>
4103  /// <param name="model">The model to match.</param>
4104  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4105  /// <param name="tag">Tag that matches the metadata model.</param>
4106  /// <returns>Unique search handle that can be used to call FindNextMetadata or FindCloseMetadata.
4107  /// Null if the metadata model does not exist.</returns>
4108  /// <exception cref="ArgumentNullException">
4109  /// <paramref name="dib"/> is null.</exception>
4110  public static FIMETADATA FindFirstMetadata(
4111  FREE_IMAGE_MDMODEL model,
4112  FIBITMAP dib,
4113  out MetadataTag tag)
4114  {
4115  if (dib.IsNull)
4116  {
4117  throw new ArgumentNullException("dib");
4118  }
4119  FITAG _tag;
4120  FIMETADATA result = FindFirstMetadata(model, dib, out _tag);
4121  if (result.IsNull)
4122  {
4123  tag = null;
4124  return result;
4125  }
4126  tag = new MetadataTag(_tag, model);
4127  if (metaDataSearchHandler.ContainsKey(result))
4128  {
4129  metaDataSearchHandler[result] = model;
4130  }
4131  else
4132  {
4133  metaDataSearchHandler.Add(result, model);
4134  }
4135  return result;
4136  }
4137 
4138  /// <summary>
4139  /// Find the next tag, if any, that matches the metadata model argument in a previous call
4140  /// to FindFirstMetadata, and then alters the tag object contents accordingly.
4141  /// </summary>
4142  /// <param name="mdhandle">Unique search handle provided by FindFirstMetadata.</param>
4143  /// <param name="tag">Tag that matches the metadata model.</param>
4144  /// <returns>Returns true on success, false on failure.</returns>
4145  public static bool FindNextMetadata(FIMETADATA mdhandle, out MetadataTag tag)
4146  {
4147  FITAG _tag;
4148  bool result;
4149  if (FindNextMetadata(mdhandle, out _tag))
4150  {
4151  tag = new MetadataTag(_tag, metaDataSearchHandler[mdhandle]);
4152  result = true;
4153  }
4154  else
4155  {
4156  tag = null;
4157  result = false;
4158  }
4159  return result;
4160  }
4161 
4162  /// <summary>
4163  /// Closes the specified metadata search handle and releases associated resources.
4164  /// </summary>
4165  /// <param name="mdhandle">The handle to close.</param>
4166  public static void FindCloseMetadata(FIMETADATA mdhandle)
4167  {
4168  if (metaDataSearchHandler.ContainsKey(mdhandle))
4169  {
4170  metaDataSearchHandler.Remove(mdhandle);
4171  }
4172  FindCloseMetadata_(mdhandle);
4173  }
4174 
4175  /// <summary>
4176  /// This dictionary links FIMETADATA handles and FREE_IMAGE_MDMODEL models.
4177  /// </summary>
4178  private static Dictionary<FIMETADATA, FREE_IMAGE_MDMODEL> metaDataSearchHandler
4179  = new Dictionary<FIMETADATA, FREE_IMAGE_MDMODEL>(1);
4180 
4181  #endregion
4182 
4183  #region Rotation and Flipping
4184 
4185  /// <summary>
4186  /// This function rotates a 1-, 8-bit greyscale or a 24-, 32-bit color image by means of 3 shears.
4187  /// 1-bit images rotation is limited to integer multiple of 90°.
4188  /// <c>null</c> is returned for other values.
4189  /// </summary>
4190  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4191  /// <param name="angle">The angle of rotation.</param>
4192  /// <returns>Handle to a FreeImage bitmap.</returns>
4193  public static FIBITMAP Rotate(FIBITMAP dib, double angle)
4194  {
4195  return Rotate(dib, angle, IntPtr.Zero);
4196  }
4197 
4198  /// <summary>
4199  /// This function rotates a 1-, 8-bit greyscale or a 24-, 32-bit color image by means of 3 shears.
4200  /// 1-bit images rotation is limited to integer multiple of 90°.
4201  /// <c>null</c> is returned for other values.
4202  /// </summary>
4203  /// <typeparam name="T">The type of the color to use as background.</typeparam>
4204  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4205  /// <param name="angle">The angle of rotation.</param>
4206  /// <param name="backgroundColor">The color used used to fill the bitmap's background.</param>
4207  /// <returns>Handle to a FreeImage bitmap.</returns>
4208  public static FIBITMAP Rotate<T>(FIBITMAP dib, double angle, T? backgroundColor) where T : struct
4209  {
4210  if (backgroundColor.HasValue)
4211  {
4212  GCHandle handle = new GCHandle();
4213  try
4214  {
4215  T[] buffer = new T[] { backgroundColor.Value };
4216  handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
4217  return Rotate(dib, angle, handle.AddrOfPinnedObject());
4218  }
4219  finally
4220  {
4221  if (handle.IsAllocated)
4222  handle.Free();
4223  }
4224  }
4225  else
4226  {
4227  return Rotate(dib, angle, IntPtr.Zero);
4228  }
4229  }
4230 
4231  /// <summary>
4232  /// Rotates a 4-bit color FreeImage bitmap.
4233  /// Allowed values for <paramref name="angle"/> are 90, 180 and 270.
4234  /// In case <paramref name="angle"/> is 0 or 360 a clone is returned.
4235  /// 0 is returned for other values or in case the rotation fails.
4236  /// </summary>
4237  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4238  /// <param name="angle">The angle of rotation.</param>
4239  /// <returns>Handle to a FreeImage bitmap.</returns>
4240  /// <remarks>
4241  /// This function is kind of temporary due to FreeImage's lack of
4242  /// rotating 4-bit images. It's particularly used by <see cref="FreeImageBitmap"/>'s
4243  /// method RotateFlip. This function will be removed as soon as FreeImage
4244  /// supports rotating 4-bit images.
4245  /// </remarks>
4246  /// <exception cref="ArgumentNullException">
4247  /// <paramref name="dib"/> is null.</exception>
4248  public static unsafe FIBITMAP Rotate4bit(FIBITMAP dib, double angle)
4249  {
4250  if (dib.IsNull)
4251  {
4252  throw new ArgumentNullException("dib");
4253  }
4254 
4255  FIBITMAP result = new FIBITMAP();
4256  int ang = (int)angle;
4257 
4258  if ((GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP) &&
4259  (GetBPP(dib) == 4) &&
4260  ((ang % 90) == 0))
4261  {
4262  int width, height, xOrg, yOrg;
4263  Scanline<FI4BIT>[] src, dst;
4264  width = (int)GetWidth(dib);
4265  height = (int)GetHeight(dib);
4266  byte index = 0;
4267  switch (ang)
4268  {
4269  case 90:
4270  result = Allocate(height, width, 4, 0, 0, 0);
4271  if (result.IsNull)
4272  {
4273  break;
4274  }
4275  CopyPalette(dib, result);
4276  src = Get04BitScanlines(dib);
4277  dst = Get04BitScanlines(result);
4278  for (int y = 0; y < width; y++)
4279  {
4280  yOrg = height - 1;
4281  for (int x = 0; x < height; x++, yOrg--)
4282  {
4283  index = src[yOrg][y];
4284  dst[y][x] = index;
4285  }
4286  }
4287  break;
4288  case 180:
4289  result = Allocate(width, height, 4, 0, 0, 0);
4290  if (result.IsNull)
4291  {
4292  break;
4293  }
4294  CopyPalette(dib, result);
4295  src = Get04BitScanlines(dib);
4296  dst = Get04BitScanlines(result);
4297 
4298  yOrg = height - 1;
4299  for (int y = 0; y < height; y++, yOrg--)
4300  {
4301  xOrg = width - 1;
4302  for (int x = 0; x < width; x++, xOrg--)
4303  {
4304  index = src[yOrg][xOrg];
4305  dst[y][x] = index;
4306  }
4307  }
4308  break;
4309  case 270:
4310  result = Allocate(height, width, 4, 0, 0, 0);
4311  if (result.IsNull)
4312  {
4313  break;
4314  }
4315  CopyPalette(dib, result);
4316  src = Get04BitScanlines(dib);
4317  dst = Get04BitScanlines(result);
4318  xOrg = width - 1;
4319  for (int y = 0; y < width; y++, xOrg--)
4320  {
4321  for (int x = 0; x < height; x++)
4322  {
4323  index = src[x][xOrg];
4324  dst[y][x] = index;
4325  }
4326  }
4327  break;
4328  case 0:
4329  case 360:
4330  result = Clone(dib);
4331  break;
4332  }
4333  }
4334  return result;
4335  }
4336 
4337  #endregion
4338 
4339  #region Upsampling / downsampling
4340 
4341  /// <summary>
4342  /// Enlarges or shrinks the FreeImage bitmap selectively per side and fills newly added areas
4343  /// with the specified background color. See remarks for further details.
4344  /// </summary>
4345  /// <typeparam name="T">The type of the specified color.</typeparam>
4346  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4347  /// <param name="left">The number of pixels, the image should be enlarged on its left side.
4348  /// Negative values shrink the image on its left side.</param>
4349  /// <param name="top">The number of pixels, the image should be enlarged on its top side.
4350  /// Negative values shrink the image on its top side.</param>
4351  /// <param name="right">The number of pixels, the image should be enlarged on its right side.
4352  /// Negative values shrink the image on its right side.</param>
4353  /// <param name="bottom">The number of pixels, the image should be enlarged on its bottom side.
4354  /// Negative values shrink the image on its bottom side.</param>
4355  /// <param name="color">The color, the enlarged sides of the image should be filled with.</param>
4356  /// <param name="options">Options that affect the color search process for palletized images.</param>
4357  /// <returns>Handle to a FreeImage bitmap.</returns>
4358  /// <remarks>
4359  /// This function enlarges or shrinks an image selectively per side.
4360  /// The main purpose of this function is to add borders to an image.
4361  /// To add a border to any of the image's sides, a positive integer value must be passed in
4362  /// any of the parameters <paramref name="left"/>, <paramref name="top"/>, <paramref name="right"/>
4363  /// or <paramref name="bottom"/>. This value represents the border's
4364  /// width in pixels. Newly created parts of the image (the border areas) are filled with the
4365  /// specified <paramref name="color"/>.
4366  /// Specifying a negative integer value for a certain side, will shrink or crop the image on
4367  /// this side. Consequently, specifying zero for a certain side will not change the image's
4368  /// extension on that side.
4369  /// <para/>
4370  /// So, calling this function with all parameters <paramref name="left"/>, <paramref name="top"/>,
4371  /// <paramref name="right"/> and <paramref name="bottom"/> set to zero, is
4372  /// effectively the same as calling function <see cref="Clone"/>; setting all parameters
4373  /// <paramref name="left"/>, <paramref name="top"/>, <paramref name="right"/> and
4374  /// <paramref name="bottom"/> to value equal to or smaller than zero, my easily be substituted
4375  /// by a call to function <see cref="Copy"/>. Both these cases produce a new image, which is
4376  /// guaranteed not to be larger than the input image. Thus, since the specified
4377  /// <paramref name="color"/> is not needed in these cases, <paramref name="color"/>
4378  /// may be <c>null</c>.
4379  /// <para/>
4380  /// Both parameters <paramref name="color"/> and <paramref name="options"/> work according to
4381  /// function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the documentation of
4382  /// <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters <paramref name="color"/>
4383  /// and <paramref name="options"/>. For palletized images, the palette of the input image is
4384  /// transparently copied to the newly created enlarged or shrunken image, so any color look-ups
4385  /// are performed on this palette.
4386  /// </remarks>
4387  /// <example>
4388  /// // create a white color<br/>
4389  /// RGBQUAD c;<br/>
4390  /// c.rgbRed = 0xFF;<br/>
4391  /// c.rgbGreen = 0xFF;<br/>
4392  /// c.rgbBlue = 0xFF;<br/>
4393  /// c.rgbReserved = 0x00;<br/>
4394  /// <br/>
4395  /// // add a white, symmetric 10 pixel wide border to the image<br/>
4396  /// dib2 = FreeImage_EnlargeCanvas(dib, 10, 10, 10, 10, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
4397  /// <br/>
4398  /// // add white, 20 pixel wide stripes to the top and bottom side of the image<br/>
4399  /// dib3 = FreeImage_EnlargeCanvas(dib, 0, 20, 0, 20, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
4400  /// <br/>
4401  /// // add white, 30 pixel wide stripes to the right side of the image and<br/>
4402  /// // cut off the 40 leftmost pixel columns<br/>
4403  /// dib3 = FreeImage_EnlargeCanvas(dib, -40, 0, 30, 0, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
4404  /// </example>
4405  public static FIBITMAP EnlargeCanvas<T>(FIBITMAP dib, int left, int top, int right, int bottom,
4406  T? color, FREE_IMAGE_COLOR_OPTIONS options) where T : struct
4407  {
4408  if (dib.IsNull)
4409  return FIBITMAP.Zero;
4410 
4411  if (color.HasValue)
4412  {
4413  if (!CheckColorType(GetImageType(dib), color.Value))
4414  return FIBITMAP.Zero;
4415 
4416  GCHandle handle = new GCHandle();
4417  try
4418  {
4419  T[] buffer = new T[] { color.Value };
4420  handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
4421  return EnlargeCanvas(dib, left, top, right, bottom, handle.AddrOfPinnedObject(), options);
4422  }
4423  finally
4424  {
4425  if (handle.IsAllocated)
4426  handle.Free();
4427  }
4428  }
4429  else
4430  {
4431  return EnlargeCanvas(dib, left, top, right, bottom, IntPtr.Zero, options);
4432  }
4433  }
4434 
4435  #endregion
4436 
4437  #region Color
4438 
4439  /// <summary>
4440  /// Sets all pixels of the specified image to the color provided through the
4441  /// <paramref name="color"/> parameter. See remarks for further details.
4442  /// </summary>
4443  /// <typeparam name="T">The type of the specified color.</typeparam>
4444  /// <param name="dib">Handle to a FreeImage bitmap.</param>
4445  /// <param name="color">The color to fill the bitmap with. See remarks for further details.</param>
4446  /// <param name="options">Options that affect the color search process for palletized images.</param>
4447  /// <returns><c>true</c> on success, <c>false</c> on failure.</returns>
4448  /// <remarks>
4449  /// This function sets all pixels of an image to the color provided through
4450  /// the <paramref name="color"/> parameter. <see cref="RGBQUAD"/> is used for standard type images.
4451  /// For non standard type images the underlaying structure is used.
4452  /// <para/>
4453  /// So, <paramref name="color"/> must be of type <see cref="Double"/>, if the image to be filled is of type
4454  /// <see cref="FREE_IMAGE_TYPE.FIT_DOUBLE"/> and must be a <see cref="FIRGBF"/> structure if the
4455  /// image is of type <see cref="FREE_IMAGE_TYPE.FIT_RGBF"/> and so on.
4456  /// <para/>
4457  /// However, the fill color is always specified through a <see cref="RGBQUAD"/> structure
4458  /// for all images of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/>.
4459  /// So, for 32- and 24-bit images, the red, green and blue members of the <see cref="RGBQUAD"/>
4460  /// structure are directly used for the image's red, green and blue channel respectively.
4461  /// Although alpha transparent <see cref="RGBQUAD"/> colors are
4462  /// supported, the alpha channel of a 32-bit image never gets modified by this function.
4463  /// A fill color with an alpha value smaller than 255 gets blended with the image's actual
4464  /// background color, which is determined from the image's bottom-left pixel.
4465  /// So, currently using alpha enabled colors, assumes the image to be unicolor before the
4466  /// fill operation. However, the <see cref="RGBQUAD.rgbReserved"/> field is only taken into account,
4467  /// if option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_RGBA"/> has been specified.
4468  /// <para/>
4469  /// For 16-bit images, the red-, green- and blue components of the specified color are
4470  /// transparently translated into either the 16-bit 555 or 565 representation. This depends
4471  /// on the image's actual red- green- and blue masks.
4472  /// <para/>
4473  /// Special attention must be payed for palletized images. Generally, the RGB color specified
4474  /// is looked up in the image's palette. The found palette index is then used to fill the image.
4475  /// There are some option flags, that affect this lookup process:
4476  /// <list type="table">
4477  /// <listheader>
4478  /// <term>Value</term>
4479  /// <description>Meaning</description>
4480  /// </listheader>
4481  /// <item>
4482  /// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_DEFAULT"/></term>
4483  /// <description>
4484  /// Uses the color, that is nearest to the specified color.
4485  /// This is the default behavior and should always find a
4486  /// color in the palette. However, the visual result may
4487  /// far from what was expected and mainly depends on the
4488  /// image's palette.
4489  /// </description>
4490  /// </item>
4491  /// <item>
4492  /// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_EQUAL_COLOR"/></term>
4493  /// <description>
4494  /// Searches the image's palette for the specified color
4495  /// but only uses the returned palette index, if the specified
4496  /// color exactly matches the palette entry. Of course,
4497  /// depending on the image's actual palette entries, this
4498  /// operation may fail. In this case, the function falls back
4499  /// to option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
4500  /// and uses the RGBQUAD's rgbReserved member (or its low nibble for 4-bit images
4501  /// or its least significant bit (LSB) for 1-bit images) as
4502  /// the palette index used for the fill operation.
4503  /// </description>
4504  /// </item>
4505  /// <item>
4506  /// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/></term>
4507  /// <description>
4508  /// Does not perform any color lookup from the palette, but
4509  /// uses the RGBQUAD's alpha channel member rgbReserved as
4510  /// the palette index to be used for the fill operation.
4511  /// However, for 4-bit images, only the low nibble of the
4512  /// rgbReserved member are used and for 1-bit images, only
4513  /// the least significant bit (LSB) is used.
4514  /// </description>
4515  /// </item>
4516  /// </list>
4517  /// </remarks>
4518  public static bool FillBackground<T>(FIBITMAP dib, T color, FREE_IMAGE_COLOR_OPTIONS options)
4519  where T : struct
4520  {
4521  if (dib.IsNull)
4522  return false;
4523 
4524  if (!CheckColorType(GetImageType(dib), color))
4525  return false;
4526 
4527  GCHandle handle = new GCHandle();
4528  try
4529  {
4530  T[] buffer = new T[] { color };
4531  handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
4532  return FillBackground(dib, handle.AddrOfPinnedObject(), options);
4533  }
4534  finally
4535  {
4536  if (handle.IsAllocated)
4537  handle.Free();
4538  }
4539  }
4540 
4541  #endregion
4542 
4543  #region Wrapper functions
4544 
4545  /// <summary>
4546  /// Returns the next higher possible color depth.
4547  /// </summary>
4548  /// <param name="bpp">Color depth to increase.</param>
4549  /// <returns>The next higher color depth or 0 if there is no valid color depth.</returns>
4550  internal static int GetNextColorDepth(int bpp)
4551  {
4552  int result = 0;
4553  switch (bpp)
4554  {
4555  case 1:
4556  result = 4;
4557  break;
4558  case 4:
4559  result = 8;
4560  break;
4561  case 8:
4562  result = 16;
4563  break;
4564  case 16:
4565  result = 24;
4566  break;
4567  case 24:
4568  result = 32;
4569  break;
4570  }
4571  return result;
4572  }
4573 
4574  /// <summary>
4575  /// Returns the next lower possible color depth.
4576  /// </summary>
4577  /// <param name="bpp">Color depth to decrease.</param>
4578  /// <returns>The next lower color depth or 0 if there is no valid color depth.</returns>
4579  internal static int GetPrevousColorDepth(int bpp)
4580  {
4581  int result = 0;
4582  switch (bpp)
4583  {
4584  case 32:
4585  result = 24;
4586  break;
4587  case 24:
4588  result = 16;
4589  break;
4590  case 16:
4591  result = 8;
4592  break;
4593  case 8:
4594  result = 4;
4595  break;
4596  case 4:
4597  result = 1;
4598  break;
4599  }
4600  return result;
4601  }
4602 
4603  /// <summary>
4604  /// Reads a null-terminated c-string.
4605  /// </summary>
4606  /// <param name="ptr">Pointer to the first char of the string.</param>
4607  /// <returns>The converted string.</returns>
4608  internal static unsafe string PtrToStr(byte* ptr)
4609  {
4610  string result = null;
4611  if (ptr != null)
4612  {
4613  System.Text.StringBuilder sb = new System.Text.StringBuilder();
4614 
4615  while (*ptr != 0)
4616  {
4617  sb.Append((char)(*(ptr++)));
4618  }
4619  result = sb.ToString();
4620  }
4621  return result;
4622  }
4623 
4624  internal static unsafe byte[] CreateShrunkenPaletteLUT(FIBITMAP dib, out int uniqueColors)
4625  {
4626  byte[] result = null;
4627  uniqueColors = 0;
4628 
4629  if ((!dib.IsNull) && (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP) && (GetBPP(dib) <= 8))
4630  {
4631  int size = (int)GetColorsUsed(dib);
4632  List<RGBQUAD> newPalette = new List<RGBQUAD>(size);
4633  List<byte> lut = new List<byte>(size);
4634  RGBQUAD* palette = (RGBQUAD*)GetPalette(dib);
4635  RGBQUAD color;
4636  int index;
4637 
4638  for (int i = 0; i < size; i++)
4639  {
4640  color = palette[i];
4641  color.rgbReserved = 255; // ignore alpha
4642 
4643  index = newPalette.IndexOf(color);
4644  if (index < 0)
4645  {
4646  newPalette.Add(color);
4647  lut.Add((byte)(newPalette.Count - 1));
4648  }
4649  else
4650  {
4651  lut.Add((byte)index);
4652  }
4653  }
4654  result = lut.ToArray();
4655  uniqueColors = newPalette.Count;
4656  }
4657  return result;
4658  }
4659 
4660  internal static PropertyItem CreatePropertyItem()
4661  {
4662  return (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);
4663  }
4664 
4665  private static unsafe void CopyPalette(FIBITMAP src, FIBITMAP dst)
4666  {
4667  RGBQUAD* orgPal = (RGBQUAD*)GetPalette(src);
4668  RGBQUAD* newPal = (RGBQUAD*)GetPalette(dst);
4669  uint size = (uint)(sizeof(RGBQUAD) * GetColorsUsed(src));
4670  CopyMemory(newPal, orgPal, size);
4671  }
4672 
4673  private static unsafe Scanline<FI4BIT>[] Get04BitScanlines(FIBITMAP dib)
4674  {
4675  int height = (int)GetHeight(dib);
4676  Scanline<FI4BIT>[] array = new Scanline<FI4BIT>[height];
4677  for (int i = 0; i < height; i++)
4678  {
4679  array[i] = new Scanline<FI4BIT>(dib, i);
4680  }
4681  return array;
4682  }
4683 
4684  /// <summary>
4685  /// Changes a bitmaps color depth.
4686  /// Used by SaveEx and SaveToStream.
4687  /// </summary>
4688  private static FIBITMAP PrepareBitmapColorDepth(FIBITMAP dibToSave, FREE_IMAGE_FORMAT format, FREE_IMAGE_COLOR_DEPTH colorDepth)
4689  {
4690  FREE_IMAGE_TYPE type = GetImageType(dibToSave);
4691  if (type == FREE_IMAGE_TYPE.FIT_BITMAP)
4692  {
4693  int bpp = (int)GetBPP(dibToSave);
4694  int targetBpp = (int)(colorDepth & FREE_IMAGE_COLOR_DEPTH.FICD_COLOR_MASK);
4695 
4696  if (colorDepth != FREE_IMAGE_COLOR_DEPTH.FICD_AUTO)
4697  {
4698  // A fix colordepth was chosen
4699  if (FIFSupportsExportBPP(format, targetBpp))
4700  {
4701  dibToSave = ConvertColorDepth(dibToSave, colorDepth, false);
4702  }
4703  else
4704  {
4705  throw new ArgumentException("FreeImage\n\nFreeImage Library plugin " +
4706  GetFormatFromFIF(format) + " is unable to write images with a color depth of " +
4707  targetBpp + " bpp.");
4708  }
4709  }
4710  else
4711  {
4712  // Auto selection was chosen
4713  if (!FIFSupportsExportBPP(format, bpp))
4714  {
4715  // The color depth is not supported
4716  int bppUpper = bpp;
4717  int bppLower = bpp;
4718  // Check from the bitmaps current color depth in both directions
4719  do
4720  {
4721  bppUpper = GetNextColorDepth(bppUpper);
4722  if (FIFSupportsExportBPP(format, bppUpper))
4723  {
4724  dibToSave = ConvertColorDepth(dibToSave, (FREE_IMAGE_COLOR_DEPTH)bppUpper, false);
4725  break;
4726  }
4727  bppLower = GetPrevousColorDepth(bppLower);
4728  if (FIFSupportsExportBPP(format, bppLower))
4729  {
4730  dibToSave = ConvertColorDepth(dibToSave, (FREE_IMAGE_COLOR_DEPTH)bppLower, false);
4731  break;
4732  }
4733  } while (!((bppLower == 0) && (bppUpper == 0)));
4734  }
4735  }
4736  }
4737  return dibToSave;
4738  }
4739 
4740  /// <summary>
4741  /// Compares blocks of memory.
4742  /// </summary>
4743  /// <param name="buf1">A pointer to a block of memory to compare.</param>
4744  /// <param name="buf2">A pointer to a block of memory to compare.</param>
4745  /// <param name="length">Specifies the number of bytes to be compared.</param>
4746  /// <returns>true, if all bytes compare as equal, false otherwise.</returns>
4747  public static unsafe bool CompareMemory(void* buf1, void* buf2, uint length)
4748  {
4749  return (length == RtlCompareMemory(buf1, buf2, length));
4750  }
4751 
4752  /// <summary>
4753  /// Compares blocks of memory.
4754  /// </summary>
4755  /// <param name="buf1">A pointer to a block of memory to compare.</param>
4756  /// <param name="buf2">A pointer to a block of memory to compare.</param>
4757  /// <param name="length">Specifies the number of bytes to be compared.</param>
4758  /// <returns>true, if all bytes compare as equal, false otherwise.</returns>
4759  public static unsafe bool CompareMemory(void* buf1, void* buf2, long length)
4760  {
4761  return (length == RtlCompareMemory(buf1, buf2, checked((uint)length)));
4762  }
4763 
4764  /// <summary>
4765  /// Compares blocks of memory.
4766  /// </summary>
4767  /// <param name="buf1">A pointer to a block of memory to compare.</param>
4768  /// <param name="buf2">A pointer to a block of memory to compare.</param>
4769  /// <param name="length">Specifies the number of bytes to be compared.</param>
4770  /// <returns>true, if all bytes compare as equal, false otherwise.</returns>
4771  public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, uint length)
4772  {
4773  return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), length));
4774  }
4775 
4776  /// <summary>
4777  /// Compares blocks of memory.
4778  /// </summary>
4779  /// <param name="buf1">A pointer to a block of memory to compare.</param>
4780  /// <param name="buf2">A pointer to a block of memory to compare.</param>
4781  /// <param name="length">Specifies the number of bytes to be compared.</param>
4782  /// <returns>true, if all bytes compare as equal, false otherwise.</returns>
4783  public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, long length)
4784  {
4785  return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), checked((uint)length)));
4786  }
4787 
4788  /// <summary>
4789  /// Moves a block of memory from one location to another.
4790  /// </summary>
4791  /// <param name="dst">A pointer to the starting address of the move destination.</param>
4792  /// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
4793  /// <param name="size">The size of the block of memory to move, in bytes.</param>
4794  public static unsafe void MoveMemory(void* dst, void* src, long size)
4795  {
4796  MoveMemory(dst, src, checked((uint)size));
4797  }
4798 
4799  /// <summary>
4800  /// Moves a block of memory from one location to another.
4801  /// </summary>
4802  /// <param name="dst">A pointer to the starting address of the move destination.</param>
4803  /// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
4804  /// <param name="size">The size of the block of memory to move, in bytes.</param>
4805  public static unsafe void MoveMemory(IntPtr dst, IntPtr src, uint size)
4806  {
4807  MoveMemory(dst.ToPointer(), src.ToPointer(), size);
4808  }
4809 
4810  /// <summary>
4811  /// Moves a block of memory from one location to another.
4812  /// </summary>
4813  /// <param name="dst">A pointer to the starting address of the move destination.</param>
4814  /// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
4815  /// <param name="size">The size of the block of memory to move, in bytes.</param>
4816  public static unsafe void MoveMemory(IntPtr dst, IntPtr src, long size)
4817  {
4818  MoveMemory(dst.ToPointer(), src.ToPointer(), checked((uint)size));
4819  }
4820 
4821  /// <summary>
4822  /// Copies a block of memory from one location to another.
4823  /// </summary>
4824  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4825  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4826  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4827  /// <remarks>
4828  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, uint)"/>.
4829  /// However, if both blocks overlap the result is undefined.
4830  /// </remarks>
4831  public static unsafe void CopyMemory(byte* dest, byte* src, int len)
4832  {
4833  if (len >= 0x10)
4834  {
4835  do
4836  {
4837  *((int*)dest) = *((int*)src);
4838  *((int*)(dest + 4)) = *((int*)(src + 4));
4839  *((int*)(dest + 8)) = *((int*)(src + 8));
4840  *((int*)(dest + 12)) = *((int*)(src + 12));
4841  dest += 0x10;
4842  src += 0x10;
4843  }
4844  while ((len -= 0x10) >= 0x10);
4845  }
4846  if (len > 0)
4847  {
4848  if ((len & 8) != 0)
4849  {
4850  *((int*)dest) = *((int*)src);
4851  *((int*)(dest + 4)) = *((int*)(src + 4));
4852  dest += 8;
4853  src += 8;
4854  }
4855  if ((len & 4) != 0)
4856  {
4857  *((int*)dest) = *((int*)src);
4858  dest += 4;
4859  src += 4;
4860  }
4861  if ((len & 2) != 0)
4862  {
4863  *((short*)dest) = *((short*)src);
4864  dest += 2;
4865  src += 2;
4866  }
4867  if ((len & 1) != 0)
4868  {
4869  *dest = *src;
4870  }
4871  }
4872  }
4873 
4874  /// <summary>
4875  /// Copies a block of memory from one location to another.
4876  /// </summary>
4877  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4878  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4879  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4880  /// <remarks>
4881  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, long)"/>.
4882  /// However, if both blocks overlap the result is undefined.
4883  /// </remarks>
4884  public static unsafe void CopyMemory(byte* dest, byte* src, long len)
4885  {
4886  CopyMemory(dest, src, checked((int)len));
4887  }
4888 
4889  /// <summary>
4890  /// Copies a block of memory from one location to another.
4891  /// </summary>
4892  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4893  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4894  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4895  /// <remarks>
4896  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, long)"/>.
4897  /// However, if both blocks overlap the result is undefined.
4898  /// </remarks>
4899  public static unsafe void CopyMemory(void* dest, void* src, long len)
4900  {
4901  CopyMemory((byte*)dest, (byte*)src, checked((int)len));
4902  }
4903 
4904  /// <summary>
4905  /// Copies a block of memory from one location to another.
4906  /// </summary>
4907  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4908  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4909  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4910  /// <remarks>
4911  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, uint)"/>.
4912  /// However, if both blocks overlap the result is undefined.
4913  /// </remarks>
4914  public static unsafe void CopyMemory(void* dest, void* src, int len)
4915  {
4916  CopyMemory((byte*)dest, (byte*)src, len);
4917  }
4918 
4919  /// <summary>
4920  /// Copies a block of memory from one location to another.
4921  /// </summary>
4922  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4923  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4924  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4925  /// <remarks>
4926  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(IntPtr, IntPtr, uint)"/>.
4927  /// However, if both blocks overlap the result is undefined.
4928  /// </remarks>
4929  public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int len)
4930  {
4931  CopyMemory((byte*)dest, (byte*)src, len);
4932  }
4933 
4934  /// <summary>
4935  /// Copies a block of memory from one location to another.
4936  /// </summary>
4937  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
4938  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4939  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4940  /// <remarks>
4941  /// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(IntPtr, IntPtr, long)"/>.
4942  /// However, if both blocks overlap the result is undefined.
4943  /// </remarks>
4944  public static unsafe void CopyMemory(IntPtr dest, IntPtr src, long len)
4945  {
4946  CopyMemory((byte*)dest, (byte*)src, checked((int)len));
4947  }
4948 
4949  /// <summary>
4950  /// Copies a block of memory into an array.
4951  /// </summary>
4952  /// <param name="dest">An array used as the destination of the copy process.</param>
4953  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4954  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4955  public static unsafe void CopyMemory(Array dest, void* src, int len)
4956  {
4957  GCHandle handle = GCHandle.Alloc(dest, GCHandleType.Pinned);
4958  try
4959  {
4960  CopyMemory((byte*)handle.AddrOfPinnedObject(), (byte*)src, len);
4961  }
4962  finally
4963  {
4964  handle.Free();
4965  }
4966  }
4967 
4968  /// <summary>
4969  /// Copies a block of memory into an array.
4970  /// </summary>
4971  /// <param name="dest">An array used as the destination of the copy process.</param>
4972  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4973  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4974  public static unsafe void CopyMemory(Array dest, void* src, long len)
4975  {
4976  CopyMemory(dest, (byte*)src, checked((int)len));
4977  }
4978 
4979  /// <summary>
4980  /// Copies a block of memory into an array.
4981  /// </summary>
4982  /// <param name="dest">An array used as the destination of the copy process.</param>
4983  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4984  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4985  public static unsafe void CopyMemory(Array dest, IntPtr src, int len)
4986  {
4987  CopyMemory(dest, (byte*)src, len);
4988  }
4989 
4990  /// <summary>
4991  /// Copies a block of memory into an array.
4992  /// </summary>
4993  /// <param name="dest">An array used as the destination of the copy process.</param>
4994  /// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
4995  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
4996  public static unsafe void CopyMemory(Array dest, IntPtr src, long len)
4997  {
4998  CopyMemory(dest, (byte*)src, checked((int)len));
4999  }
5000 
5001  /// <summary>
5002  /// Copies the content of an array to a memory location.
5003  /// </summary>
5004  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
5005  /// <param name="src">An array used as the source of the copy process.</param>
5006  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
5007  public static unsafe void CopyMemory(void* dest, Array src, int len)
5008  {
5009  GCHandle handle = GCHandle.Alloc(src, GCHandleType.Pinned);
5010  try
5011  {
5012  CopyMemory((byte*)dest, (byte*)handle.AddrOfPinnedObject(), len);
5013  }
5014  finally
5015  {
5016  handle.Free();
5017  }
5018  }
5019 
5020  /// <summary>
5021  /// Copies the content of an array to a memory location.
5022  /// </summary>
5023  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
5024  /// <param name="src">An array used as the source of the copy process.</param>
5025  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
5026  public static unsafe void CopyMemory(void* dest, Array src, long len)
5027  {
5028  CopyMemory((byte*)dest, src, checked((int)len));
5029  }
5030 
5031  /// <summary>
5032  /// Copies the content of an array to a memory location.
5033  /// </summary>
5034  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
5035  /// <param name="src">An array used as the source of the copy process.</param>
5036  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
5037  public static unsafe void CopyMemory(IntPtr dest, Array src, int len)
5038  {
5039  CopyMemory((byte*)dest, src, len);
5040  }
5041 
5042  /// <summary>
5043  /// Copies the content of an array to a memory location.
5044  /// </summary>
5045  /// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
5046  /// <param name="src">An array used as the source of the copy process.</param>
5047  /// <param name="len">The size of the block of memory to copy, in bytes.</param>
5048  public static unsafe void CopyMemory(IntPtr dest, Array src, long len)
5049  {
5050  CopyMemory((byte*)dest, src, checked((int)len));
5051  }
5052 
5053  /// <summary>
5054  /// Copies the content of one array into another array.
5055  /// </summary>
5056  /// <param name="dest">An array used as the destination of the copy process.</param>
5057  /// <param name="src">An array used as the source of the copy process.</param>
5058  /// <param name="len">The size of the content to copy, in bytes.</param>
5059  public static unsafe void CopyMemory(Array dest, Array src, int len)
5060  {
5061  GCHandle dHandle = GCHandle.Alloc(dest, GCHandleType.Pinned);
5062  try
5063  {
5064  GCHandle sHandle = GCHandle.Alloc(src, GCHandleType.Pinned);
5065  try
5066  {
5067  CopyMemory((byte*)dHandle.AddrOfPinnedObject(), (byte*)sHandle.AddrOfPinnedObject(), len);
5068  }
5069  finally
5070  {
5071  sHandle.Free();
5072  }
5073  }
5074  finally
5075  {
5076  dHandle.Free();
5077  }
5078  }
5079 
5080  /// <summary>
5081  /// Copies the content of one array into another array.
5082  /// </summary>
5083  /// <param name="dest">An array used as the destination of the copy process.</param>
5084  /// <param name="src">An array used as the source of the copy process.</param>
5085  /// <param name="len">The size of the content to copy, in bytes.</param>
5086  public static unsafe void CopyMemory(Array dest, Array src, long len)
5087  {
5088  CopyMemory(dest, src, checked((int)len));
5089  }
5090 
5091  internal static string ColorToString(Color color)
5092  {
5093  return string.Format(
5094  System.Globalization.CultureInfo.CurrentCulture,
5095  "{{Name={0}, ARGB=({1}, {2}, {3}, {4})}}",
5096  new object[] { color.Name, color.A, color.R, color.G, color.B });
5097  }
5098 
5099  internal static void Resize(ref string str, int length)
5100  {
5101  if ((str != null) && (length >= 0) && (str.Length != length))
5102  {
5103  char[] chars = str.ToCharArray();
5104  Array.Resize(ref chars, length);
5105  str = new string(chars);
5106  }
5107  }
5108 
5109  internal static void Resize(ref string str, int min, int max)
5110  {
5111  if ((str != null) && (min >= 0) && (max >= 0) && (min <= max))
5112  {
5113  if (str.Length < min)
5114  {
5115  char[] chars = str.ToCharArray();
5116  Array.Resize(ref chars, min);
5117  str = new string(chars);
5118  }
5119  else if (str.Length > max)
5120  {
5121  char[] chars = str.ToCharArray();
5122  Array.Resize(ref chars, max);
5123  str = new string(chars);
5124  }
5125  }
5126  }
5127 
5128  internal static void Resize<T>(ref T[] array, int length)
5129  {
5130  if ((array != null) && (length >= 0) && (array.Length != length))
5131  {
5132  Array.Resize(ref array, length);
5133  }
5134  }
5135 
5136  internal static void Resize<T>(ref T[] array, int min, int max)
5137  {
5138  if ((array != null) && (min >= 0) && (max >= 0) && (min <= max))
5139  {
5140  if (array.Length < min)
5141  {
5142  Array.Resize(ref array, min);
5143  }
5144  else if (array.Length > max)
5145  {
5146  Array.Resize(ref array, max);
5147  }
5148  }
5149  }
5150 
5151  internal static bool CheckColorType<T>(FREE_IMAGE_TYPE imageType, T color)
5152  {
5153  Type type = typeof(T);
5154  bool result;
5155  switch (imageType)
5156  {
5157  case FREE_IMAGE_TYPE.FIT_BITMAP:
5158  result = (type == typeof(RGBQUAD)); break;
5159  case FREE_IMAGE_TYPE.FIT_COMPLEX:
5160  result = (type == typeof(FICOMPLEX)); break;
5161  case FREE_IMAGE_TYPE.FIT_DOUBLE:
5162  result = (type == typeof(double)); break;
5163  case FREE_IMAGE_TYPE.FIT_FLOAT:
5164  result = (type == typeof(float)); break;
5165  case FREE_IMAGE_TYPE.FIT_INT16:
5166  result = (type == typeof(Int16)); break;
5167  case FREE_IMAGE_TYPE.FIT_INT32:
5168  result = (type == typeof(Int32)); break;
5169  case FREE_IMAGE_TYPE.FIT_RGB16:
5170  result = (type == typeof(FIRGB16)); break;
5171  case FREE_IMAGE_TYPE.FIT_RGBA16:
5172  result = (type == typeof(FIRGBA16)); break;
5173  case FREE_IMAGE_TYPE.FIT_RGBAF:
5174  result = (type == typeof(FIRGBAF)); break;
5175  case FREE_IMAGE_TYPE.FIT_RGBF:
5176  result = (type == typeof(FIRGBF)); break;
5177  case FREE_IMAGE_TYPE.FIT_UINT16:
5178  result = (type == typeof(UInt16)); break;
5179  case FREE_IMAGE_TYPE.FIT_UINT32:
5180  result = (type == typeof(UInt32)); break;
5181  default:
5182  result = false; break;
5183  }
5184  return result;
5185  }
5186 
5187  #endregion
5188 
5189  #region Dll-Imports
5190 
5191  /// <summary>
5192  /// Retrieves a handle to a display device context (DC) for the client area of a specified window
5193  /// or for the entire screen. You can use the returned handle in subsequent GDI functions to draw in the DC.
5194  /// </summary>
5195  /// <param name="hWnd">Handle to the window whose DC is to be retrieved.
5196  /// If this value is IntPtr.Zero, GetDC retrieves the DC for the entire screen. </param>
5197  /// <returns>If the function succeeds, the return value is a handle to the DC for the specified window's client area.
5198  /// If the function fails, the return value is NULL.</returns>
5199  [DllImport("user32.dll")]
5200  private static extern IntPtr GetDC(IntPtr hWnd);
5201 
5202  /// <summary>
5203  /// Releases a device context (DC), freeing it for use by other applications.
5204  /// The effect of the ReleaseDC function depends on the type of DC. It frees only common and window DCs.
5205  /// It has no effect on class or private DCs.
5206  /// </summary>
5207  /// <param name="hWnd">Handle to the window whose DC is to be released.</param>
5208  /// <param name="hDC">Handle to the DC to be released.</param>
5209  /// <returns>Returns true on success, false on failure.</returns>
5210  [DllImport("user32.dll")]
5211  private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
5212 
5213  /// <summary>
5214  /// Creates a DIB that applications can write to directly.
5215  /// The function gives you a pointer to the location of the bitmap bit values.
5216  /// You can supply a handle to a file-mapping object that the function will use to create the bitmap,
5217  /// or you can let the system allocate the memory for the bitmap.
5218  /// </summary>
5219  /// <param name="hdc">Handle to a device context.</param>
5220  /// <param name="pbmi">Pointer to a BITMAPINFO structure that specifies various attributes of the DIB,
5221  /// including the bitmap dimensions and colors.</param>
5222  /// <param name="iUsage">Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure
5223  /// pointed to by pbmi (either logical palette indexes or literal RGB values).</param>
5224  /// <param name="ppvBits">Pointer to a variable that receives a pointer to the location of the DIB bit values.</param>
5225  /// <param name="hSection">Handle to a file-mapping object that the function will use to create the DIB.
5226  /// This parameter can be NULL.</param>
5227  /// <param name="dwOffset">Specifies the offset from the beginning of the file-mapping object referenced by hSection
5228  /// where storage for the bitmap bit values is to begin. This value is ignored if hSection is NULL.</param>
5229  /// <returns>If the function succeeds, the return value is a handle to the newly created DIB,
5230  /// and *ppvBits points to the bitmap bit values. If the function fails, the return value is NULL, and *ppvBits is NULL.</returns>
5231  [DllImport("gdi32.dll")]
5232  private static extern IntPtr CreateDIBSection(
5233  IntPtr hdc,
5234  [In] IntPtr pbmi,
5235  uint iUsage,
5236  out IntPtr ppvBits,
5237  IntPtr hSection,
5238  uint dwOffset);
5239 
5240  /// <summary>
5241  /// Deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object.
5242  /// After the object is deleted, the specified handle is no longer valid.
5243  /// </summary>
5244  /// <param name="hObject">Handle to a logical pen, brush, font, bitmap, region, or palette.</param>
5245  /// <returns>Returns true on success, false on failure.</returns>
5246  [DllImport("gdi32.dll")]
5247  private static extern bool DeleteObject(IntPtr hObject);
5248 
5249  /// <summary>
5250  /// Creates a compatible bitmap (DDB) from a DIB and, optionally, sets the bitmap bits.
5251  /// </summary>
5252  /// <param name="hdc">Handle to a device context.</param>
5253  /// <param name="lpbmih">Pointer to a bitmap information header structure.</param>
5254  /// <param name="fdwInit">Specifies how the system initializes the bitmap bits - (use 4).</param>
5255  /// <param name="lpbInit">Pointer to an array of bytes containing the initial bitmap data.</param>
5256  /// <param name="lpbmi">Pointer to a BITMAPINFO structure that describes the dimensions
5257  /// and color format of the array pointed to by the lpbInit parameter.</param>
5258  /// <param name="fuUsage">Specifies whether the bmiColors member of the BITMAPINFO structure
5259  /// was initialized - (use 0).</param>
5260  /// <returns>Handle to a DIB or null on failure.</returns>
5261  [DllImport("gdi32.dll")]
5262  private static extern IntPtr CreateDIBitmap(
5263  IntPtr hdc,
5264  IntPtr lpbmih,
5265  uint fdwInit,
5266  IntPtr lpbInit,
5267  IntPtr lpbmi,
5268  uint fuUsage);
5269 
5270  /// <summary>
5271  /// Retrieves information for the specified graphics object.
5272  /// </summary>
5273  /// <param name="hgdiobj">Handle to the graphics object of interest.</param>
5274  /// <param name="cbBuffer">Specifies the number of bytes of information to
5275  /// be written to the buffer.</param>
5276  /// <param name="lpvObject">Pointer to a buffer that receives the information
5277  /// about the specified graphics object.</param>
5278  /// <returns>0 on failure.</returns>
5279  [DllImport("gdi32.dll")]
5280  private static extern int GetObject(IntPtr hgdiobj, int cbBuffer, IntPtr lpvObject);
5281 
5282  /// <summary>
5283  /// Retrieves the bits of the specified compatible bitmap and copies them into a buffer
5284  /// as a DIB using the specified format.
5285  /// </summary>
5286  /// <param name="hdc">Handle to the device context.</param>
5287  /// <param name="hbmp">Handle to the bitmap. This must be a compatible bitmap (DDB).</param>
5288  /// <param name="uStartScan">Specifies the first scan line to retrieve.</param>
5289  /// <param name="cScanLines">Specifies the number of scan lines to retrieve.</param>
5290  /// <param name="lpvBits">Pointer to a buffer to receive the bitmap data.</param>
5291  /// <param name="lpbmi">Pointer to a BITMAPINFO structure that specifies the desired
5292  /// format for the DIB data.</param>
5293  /// <param name="uUsage">Specifies the format of the bmiColors member of the
5294  /// BITMAPINFO structure - (use 0).</param>
5295  /// <returns>0 on failure.</returns>
5296  [DllImport("gdi32.dll")]
5297  private static extern unsafe int GetDIBits(
5298  IntPtr hdc,
5299  IntPtr hbmp,
5300  uint uStartScan,
5301  uint cScanLines,
5302  IntPtr lpvBits,
5303  IntPtr lpbmi,
5304  uint uUsage);
5305 
5306  /// <summary>
5307  /// Moves a block of memory from one location to another.
5308  /// </summary>
5309  /// <param name="dst">Pointer to the starting address of the move destination.</param>
5310  /// <param name="src">Pointer to the starting address of the block of memory to be moved.</param>
5311  /// <param name="size">Size of the block of memory to move, in bytes.</param>
5312  [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
5313  public static unsafe extern void MoveMemory(void* dst, void* src, uint size);
5314 
5315  /// <summary>
5316  /// The RtlCompareMemory routine compares blocks of memory
5317  /// and returns the number of bytes that are equivalent.
5318  /// </summary>
5319  /// <param name="buf1">A pointer to a block of memory to compare.</param>
5320  /// <param name="buf2">A pointer to a block of memory to compare.</param>
5321  /// <param name="count">Specifies the number of bytes to be compared.</param>
5322  /// <returns>RtlCompareMemory returns the number of bytes that compare as equal.
5323  /// If all bytes compare as equal, the input Length is returned.</returns>
5324  [DllImport("ntdll.dll", EntryPoint = "RtlCompareMemory", SetLastError = false)]
5325  internal static unsafe extern uint RtlCompareMemory(void* buf1, void* buf2, uint count);
5326 
5327  #endregion
5328  }
5329 }
static readonly FIBITMAP Zero
A read-only field that represents a handle that has been initialized to zero.
Definition: FIBITMAP.cs:57
FREE_IMAGE_QUANTIZE
Color quantization algorithms. Constants used in FreeImage_ColorQuantize.
_Use_decl_annotations_ bool HasAlpha(DXGI_FORMAT fmt)
Definition: DirectXTex.inl:237
HRESULT Resize(_In_ const Image &srcImage, _In_ size_t width, _In_ size_t height, _In_ DWORD filter, _Out_ ScratchImage &image)
Structure for implementing access to custom handles.
Definition: FreeImageIO.cs:44
FREE_IMAGE_MDMODEL
Metadata models supported by FreeImage.
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float threshold
Definition: DirectXTexP.h:183
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
FREE_IMAGE_DITHER
Dithering algorithms. Constants used in FreeImage_Dither.
The clone mixin to clone the current mixins where the clone is emitted.
FREE_IMAGE_COLOR_OPTIONS
Constants used in color filling routines.
_In_ size_t count
Definition: DirectXTexP.h:174
System.IO.File File
static readonly FIMULTIBITMAP Zero
A read-only field that represents a handle that has been initialized to zero.
Manages metadata objects and operations.
Definition: MetadataTag.cs:47
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
FREE_IMAGE_COMPARE_FLAGS
List of combinable compare modes.
FREE_IMAGE_METADATA_COPY
Flags for copying data from a bitmap to another.
FREE_IMAGE_COLOR_TYPE
Image color types used in FreeImage.
System.Windows.Shapes.Rectangle Rectangle
Definition: ColorPicker.cs:16
FREE_IMAGE_SAVE_FLAGS
Flags used in save functions.
char * dest
Definition: lz4.h:61
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
Wrapper for a custom handle.
Definition: fi_handle.cs:83
FREE_IMAGE_COLOR_DEPTH
Enumeration used for color conversions. FREE_IMAGE_COLOR_DEPTH contains several colors to convert to...
FREE_IMAGE_TYPE
Image types used in FreeImage.
FREE_IMAGE_FORMAT
I/O image format identifiers.
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
string Key
Gets or sets the key of the metadata.
Definition: MetadataTag.cs:314
FREE_IMAGE_LOAD_FLAGS
Flags used in load functions.