You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
exercise_2/colmap-build/FreeImage/Wrapper/FreeImage.NET/cs/Library/FreeImageWrapper.cs

5329 lines
186 KiB

// ==========================================================
// FreeImage 3 .NET wrapper
// Original FreeImage 3 functions and .NET compatible derived functions
//
// Design and implementation by
// - Jean-Philippe Goerke (jpgoerke@users.sourceforge.net)
// - Carsten Klein (cklein05@users.sourceforge.net)
//
// Contributors:
// - David Boland (davidboland@vodafone.ie)
//
// Main reference : MSDN Knowlede Base
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================
// ==========================================================
// CVS
// $Revision: 1.19 $
// $Date: 2011/10/02 13:00:45 $
// $Id: FreeImageWrapper.cs,v 1.19 2011/10/02 13:00:45 drolon Exp $
// ==========================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using FreeImageAPI.IO;
using FreeImageAPI.Metadata;
namespace FreeImageAPI
{
/// <summary>
/// Static class importing functions from the FreeImage library
/// and providing additional functions.
/// </summary>
public static partial class FreeImage
{
#region Constants
/// <summary>
/// Array containing all 'FREE_IMAGE_MDMODEL's.
/// </summary>
public static readonly FREE_IMAGE_MDMODEL[] FREE_IMAGE_MDMODELS =
(FREE_IMAGE_MDMODEL[])Enum.GetValues(typeof(FREE_IMAGE_MDMODEL));
/// <summary>
/// Stores handles used to read from streams.
/// </summary>
private static Dictionary<FIMULTIBITMAP, fi_handle> streamHandles =
new Dictionary<FIMULTIBITMAP, fi_handle>();
/// <summary>
/// Version of the wrapper library.
/// </summary>
private static Version WrapperVersion;
private const int DIB_RGB_COLORS = 0;
private const int DIB_PAL_COLORS = 1;
private const int CBM_INIT = 0x4;
/// <summary>
/// An uncompressed format.
/// </summary>
public const int BI_RGB = 0;
/// <summary>
/// A run-length encoded (RLE) format for bitmaps with 8 bpp. The compression format is a 2-byte
/// format consisting of a count byte followed by a byte containing a color index.
/// </summary>
public const int BI_RLE8 = 1;
/// <summary>
/// An RLE format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting
/// of a count byte followed by two word-length color indexes.
/// </summary>
public const int BI_RLE4 = 2;
/// <summary>
/// Specifies that the bitmap is not compressed and that the color table consists of three
/// <b>DWORD</b> color masks that specify the red, green, and blue components, respectively,
/// of each pixel. This is valid when used with 16- and 32-bpp bitmaps.
/// </summary>
public const int BI_BITFIELDS = 3;
/// <summary>
/// <b>Windows 98/Me, Windows 2000/XP:</b> Indicates that the image is a JPEG image.
/// </summary>
public const int BI_JPEG = 4;
/// <summary>
/// <b>Windows 98/Me, Windows 2000/XP:</b> Indicates that the image is a PNG image.
/// </summary>
public const int BI_PNG = 5;
#endregion
#region General functions
/// <summary>
/// Returns the internal version of this FreeImage .NET wrapper.
/// </summary>
/// <returns>The internal version of this FreeImage .NET wrapper.</returns>
public static Version GetWrapperVersion()
{
if (WrapperVersion == null)
{
try
{
object[] attributes = Assembly.GetAssembly(typeof(FreeImage))
.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
if ((attributes != null) && (attributes.Length != 0))
{
AssemblyFileVersionAttribute attribute =
attributes[0] as AssemblyFileVersionAttribute;
if ((attribute != null) && (attribute.Version != null))
{
return (WrapperVersion = new Version(attribute.Version));
}
}
}
catch
{
}
WrapperVersion = new Version();
}
return WrapperVersion;
}
/// <summary>
/// Returns the version of the native FreeImage library.
/// </summary>
/// <returns>The version of the native FreeImage library.</returns>
public static Version GetNativeVersion()
{
return new Version(GetVersion());
}
/// <summary>
/// Returns a value indicating if the FreeImage library is available or not.
/// See remarks for further details.
/// </summary>
/// <returns><c>false</c> if the file is not available or out of date;
/// <c>true</c>, otherwise.</returns>
/// <remarks>
/// The FreeImage.NET library is a wrapper for the native C++ library
/// (FreeImage.dll ... dont mix ist up with this library FreeImageNet.dll).
/// The native library <b>must</b> be either in the same folder as the program's
/// executable or in a folder contained in the envirent variable <i>PATH</i>
/// (for example %WINDIR%\System32).<para/>
/// Further more must both libraries, including the program itself,
/// be the same architecture (x86 or x64).
/// </remarks>
public static bool IsAvailable()
{
try
{
// Call a static fast executing function
Version nativeVersion = new Version(GetVersion());
Version wrapperVersion = GetWrapperVersion();
// No exception thrown, the library seems to be present
return
(nativeVersion.Major > wrapperVersion.Major) ||
((nativeVersion.Major == wrapperVersion.Major) && (nativeVersion.Minor > wrapperVersion.Minor)) ||
((nativeVersion.Major == wrapperVersion.Major) && (nativeVersion.Minor == wrapperVersion.Minor) && (nativeVersion.Build >= wrapperVersion.Build));
}
catch (DllNotFoundException)
{
return false;
}
catch (EntryPointNotFoundException)
{
return false;
}
catch (BadImageFormatException)
{
return false;
}
}
#endregion
#region Bitmap management functions
/// <summary>
/// Creates a new bitmap in memory.
/// </summary>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new Bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP Allocate(int width, int height, int bpp)
{
return Allocate(width, height, bpp, 0, 0, 0);
}
/// <summary>
/// Creates a new bitmap in memory.
/// </summary>
/// <param name="type">Type of the image.</param>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new Bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp)
{
return AllocateT(type, width, height, bpp, 0, 0, 0);
}
/// <summary>
/// Allocates a new image of the specified width, height and bit depth and optionally
/// fills it with the specified color. See remarks for further details.
/// </summary>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.</param>
/// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
/// <param name="options">Options to enable or disable function-features.</param>
/// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function is an extension to <see cref="Allocate"/>, which additionally supports
/// specifying a palette to be set for the newly create image, as well as specifying a
/// background color, the newly created image should initially be filled with.
/// <para/>
/// Basically, this function internally relies on function <see cref="Allocate"/>, followed by a
/// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
/// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
/// documented for function <see cref="FillBackground&lt;T&gt;"/>.
/// So, please refer to the documentation of <see cref="FillBackground&lt;T&gt;"/> to
/// learn more about parameters <paramref name="color"/> and <paramref name="options"/>.
/// <para/>
/// The palette specified through parameter <paramref name="palette"/> is only copied to the
/// newly created image, if the desired bit depth is smaller than or equal to 8 bits per pixel.
/// In other words, the <paramref name="palette"/> parameter is only taken into account for
/// palletized images. So, for an 8-bit image, the length is 256, for an 4-bit image it is 16
/// and it is 2 for a 1-bit image. In other words, this function does not support partial palettes.
/// <para/>
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
/// is created. For a 1-bit image, only if the specified background color is either black or white,
/// a monochrome palette, consisting of black and white only is created. In any case, the darker
/// colors are stored at the smaller palette indices.
/// <para/>
/// If the specified background color is not a greyscale value, or is neither black nor white
/// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
/// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
/// is implicit, so the specified <paramref name="color"/> is applied to the palette entry,
/// specified by the background color's <see cref="RGBQUAD.rgbReserved"/> field.
/// The image is then filled with this palette index.
/// <para/>
/// This function returns a newly created image as function <see cref="Allocate"/> does, if both
/// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
/// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
/// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
/// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
/// However, in the latter case, this function returns an image, whose
/// pixels are all initialized with zeros so, the image will be filled with the color of the
/// first palette entry.
/// </remarks>
public static FIBITMAP AllocateEx(int width, int height, int bpp,
RGBQUAD? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette)
{
return AllocateEx(width, height, bpp, color, options, palette, 0, 0, 0);
}
/// <summary>
/// Allocates a new image of the specified width, height and bit depth and optionally
/// fills it with the specified color. See remarks for further details.
/// </summary>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.</param>
/// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
/// <param name="options">Options to enable or disable function-features.</param>
/// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
/// <param name="red_mask">Red part of the color layout.
/// eg: 0xFF0000</param>
/// <param name="green_mask">Green part of the color layout.
/// eg: 0x00FF00</param>
/// <param name="blue_mask">Blue part of the color layout.
/// eg: 0x0000FF</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function is an extension to <see cref="Allocate"/>, which additionally supports
/// specifying a palette to be set for the newly create image, as well as specifying a
/// background color, the newly created image should initially be filled with.
/// <para/>
/// Basically, this function internally relies on function <see cref="Allocate"/>, followed by a
/// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
/// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
/// documented for function <see cref="FillBackground&lt;T&gt;"/>.
/// So, please refer to the documentation of <see cref="FillBackground&lt;T&gt;"/> to
/// learn more about parameters <paramref name="color"/> and <paramref name="options"/>.
/// <para/>
/// The palette specified through parameter <paramref name="palette"/> is only copied to the
/// newly created image, if the desired bit depth is smaller than or equal to 8 bits per pixel.
/// In other words, the <paramref name="palette"/> parameter is only taken into account for
/// palletized images. So, for an 8-bit image, the length is 256, for an 4-bit image it is 16
/// and it is 2 for a 1-bit image. In other words, this function does not support partial palettes.
/// <para/>
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
/// is created. For a 1-bit image, only if the specified background color is either black or white,
/// a monochrome palette, consisting of black and white only is created. In any case, the darker
/// colors are stored at the smaller palette indices.
/// <para/>
/// If the specified background color is not a greyscale value, or is neither black nor white
/// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
/// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
/// is implicit, so the specified <paramref name="color"/> is applied to the palette entry,
/// specified by the background color's <see cref="RGBQUAD.rgbReserved"/> field.
/// The image is then filled with this palette index.
/// <para/>
/// This function returns a newly created image as function <see cref="Allocate"/> does, if both
/// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
/// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
/// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
/// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
/// However, in the latter case, this function returns an image, whose
/// pixels are all initialized with zeros so, the image will be filled with the color of the
/// first palette entry.
/// </remarks>
public static FIBITMAP AllocateEx(int width, int height, int bpp,
RGBQUAD? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette,
uint red_mask, uint green_mask, uint blue_mask)
{
if ((palette != null) && (bpp <= 8) && (palette.Length < (1 << bpp)))
return FIBITMAP.Zero;
if (color.HasValue)
{
GCHandle handle = new GCHandle();
try
{
RGBQUAD[] buffer = new RGBQUAD[] { color.Value };
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return AllocateEx(width, height, bpp, handle.AddrOfPinnedObject(),
options, palette, red_mask, green_mask, blue_mask);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
else
{
return AllocateEx(width, height, bpp, IntPtr.Zero,
options, palette, red_mask, green_mask, blue_mask);
}
}
/// <summary>
/// Allocates a new image of the specified type, width, height and bit depth and optionally
/// fills it with the specified color. See remarks for further details.
/// </summary>
/// <typeparam name="T">The type of the specified color.</typeparam>
/// <param name="type">Type of the image.</param>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
/// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
/// <param name="options">Options to enable or disable function-features.</param>
/// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function is an extension to <see cref="AllocateT"/>, which additionally supports
/// specifying a palette to be set for the newly create image, as well as specifying a
/// background color, the newly created image should initially be filled with.
/// <para/>
/// Basically, this function internally relies on function <see cref="AllocateT"/>, followed by a
/// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
/// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
/// documented for function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the
/// documentation of <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters color and options.
/// <para/>
/// The palette specified through parameter palette is only copied to the newly created
/// image, if its image type is <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> and the desired bit
/// depth is smaller than or equal to 8 bits per pixel. In other words, the <paramref name="palette"/>
/// palette is only taken into account for palletized images. However, if the preceding conditions
/// match and if <paramref name="palette"/> is not <c>null</c>, the palette is assumed to be at
/// least as large as the size of a fully populated palette for the desired bit depth.
/// So, for an 8-bit image, this length is 256, for an 4-bit image it is 16 and it is
/// 2 for a 1-bit image. In other words, this function does not support partial palettes.
/// <para/>
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
/// is created. For a 1-bit image, only if the specified background color is either black or white,
/// a monochrome palette, consisting of black and white only is created. In any case, the darker
/// colors are stored at the smaller palette indices.
/// <para/>
/// If the specified background color is not a greyscale value, or is neither black nor white
/// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
/// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
/// is implicit, so the specified color is applied to the palette entry, specified by the
/// background color's <see cref="RGBQUAD.rgbReserved"/> field. The image is then filled with
/// this palette index.
/// <para/>
/// This function returns a newly created image as function <see cref="AllocateT"/> does, if both
/// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
/// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
/// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
/// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
/// However, in the latter case, this function returns an image, whose
/// pixels are all initialized with zeros so, the image will be filled with the color of the
/// first palette entry.
/// </remarks>
public static FIBITMAP AllocateExT<T>(FREE_IMAGE_TYPE type, int width, int height, int bpp,
T? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette) where T : struct
{
return AllocateExT(type, width, height, bpp, color, options, palette, 0, 0, 0);
}
/// <summary>
/// Allocates a new image of the specified type, width, height and bit depth and optionally
/// fills it with the specified color. See remarks for further details.
/// </summary>
/// <typeparam name="T">The type of the specified color.</typeparam>
/// <param name="type">Type of the image.</param>
/// <param name="width">Width of the new bitmap.</param>
/// <param name="height">Height of the new bitmap.</param>
/// <param name="bpp">Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap</param>
/// <param name="color">The color to fill the bitmap with or <c>null</c>.</param>
/// <param name="options">Options to enable or disable function-features.</param>
/// <param name="palette">The palette of the bitmap or <c>null</c>.</param>
/// <param name="red_mask">Red part of the color layout.
/// eg: 0xFF0000</param>
/// <param name="green_mask">Green part of the color layout.
/// eg: 0x00FF00</param>
/// <param name="blue_mask">Blue part of the color layout.
/// eg: 0x0000FF</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function is an extension to <see cref="AllocateT"/>, which additionally supports
/// specifying a palette to be set for the newly create image, as well as specifying a
/// background color, the newly created image should initially be filled with.
/// <para/>
/// Basically, this function internally relies on function <see cref="AllocateT"/>, followed by a
/// call to <see cref="FillBackground&lt;T&gt;"/>. This is why both parameters
/// <paramref name="color"/> and <paramref name="options"/> behave the same as it is
/// documented for function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the
/// documentation of <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters color and options.
/// <para/>
/// The palette specified through parameter palette is only copied to the newly created
/// image, if its image type is <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> and the desired bit
/// depth is smaller than or equal to 8 bits per pixel. In other words, the <paramref name="palette"/>
/// palette is only taken into account for palletized images. However, if the preceding conditions
/// match and if <paramref name="palette"/> is not <c>null</c>, the palette is assumed to be at
/// least as large as the size of a fully populated palette for the desired bit depth.
/// So, for an 8-bit image, this length is 256, for an 4-bit image it is 16 and it is
/// 2 for a 1-bit image. In other words, this function does not support partial palettes.
/// <para/>
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if <paramref name="palette"/> is <c>null</c>.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/> is specified, a greyscale palette
/// is created. For a 1-bit image, only if the specified background color is either black or white,
/// a monochrome palette, consisting of black and white only is created. In any case, the darker
/// colors are stored at the smaller palette indices.
/// <para/>
/// If the specified background color is not a greyscale value, or is neither black nor white
/// for a 1-bit image, solely this specified color is injected into the otherwise black-initialized
/// palette. For this operation, option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
/// is implicit, so the specified color is applied to the palette entry, specified by the
/// background color's <see cref="RGBQUAD.rgbReserved"/> field. The image is then filled with
/// this palette index.
/// <para/>
/// This function returns a newly created image as function <see cref="AllocateT"/> does, if both
/// parameters <paramref name="color"/> and <paramref name="palette"/> are <c>null</c>.
/// If only <paramref name="color"/> is <c>null</c>, the palette pointed to by
/// parameter <paramref name="palette"/> is initially set for the new image, if a palletized
/// image of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> is created.
/// However, in the latter case, this function returns an image, whose
/// pixels are all initialized with zeros so, the image will be filled with the color of the
/// first palette entry.
/// </remarks>
public static FIBITMAP AllocateExT<T>(FREE_IMAGE_TYPE type, int width, int height, int bpp,
T? color, FREE_IMAGE_COLOR_OPTIONS options, RGBQUAD[] palette,
uint red_mask, uint green_mask, uint blue_mask) where T : struct
{
if ((palette != null) && (bpp <= 8) && (palette.Length < (1 << bpp)))
return FIBITMAP.Zero;
if (color.HasValue)
{
if (!CheckColorType(type, color.Value))
return FIBITMAP.Zero;
GCHandle handle = new GCHandle();
try
{
T[] buffer = new T[] { color.Value };
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return AllocateExT(type, width, height, bpp, handle.AddrOfPinnedObject(),
options, palette, red_mask, green_mask, blue_mask);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
else
{
return AllocateExT(type, width, height, bpp, IntPtr.Zero,
options, palette, red_mask, green_mask, blue_mask);
}
}
/// <summary>
/// Converts a FreeImage bitmap to a .NET <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>The converted .NET <see cref="System.Drawing.Bitmap"/>.</returns>
/// <remarks>Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.</remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The image type of <paramref name="dib"/> is not FIT_BITMAP.</exception>
public static Bitmap GetBitmap(FIBITMAP dib)
{
return GetBitmap(dib, true);
}
/// <summary>
/// Converts a FreeImage bitmap to a .NET <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="copyMetadata">When true existing metadata will be copied.</param>
/// <returns>The converted .NET <see cref="System.Drawing.Bitmap"/>.</returns>
/// <remarks>Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.</remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The image type of <paramref name="dib"/> is not FIT_BITMAP.</exception>
internal static Bitmap GetBitmap(FIBITMAP dib, bool copyMetadata)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
if (GetImageType(dib) != FREE_IMAGE_TYPE.FIT_BITMAP)
{
throw new ArgumentException("Only bitmaps with type of FIT_BITMAP can be converted.");
}
PixelFormat format = GetPixelFormat(dib);
if ((format == PixelFormat.Undefined) && (GetBPP(dib) == 16u))
{
throw new ArgumentException("Only 16bit 555 and 565 are supported.");
}
int height = (int)GetHeight(dib);
int width = (int)GetWidth(dib);
int pitch = (int)GetPitch(dib);
Bitmap result = new Bitmap(width, height, format);
BitmapData data;
// Locking the complete bitmap in writeonly mode
data = result.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, format);
// Writing the bitmap data directly into the new created .NET bitmap.
ConvertToRawBits(data.Scan0, dib, pitch, GetBPP(dib),
GetRedMask(dib), GetGreenMask(dib), GetBlueMask(dib), true);
// Unlock the bitmap
result.UnlockBits(data);
// Apply the bitmap resolution
if((GetResolutionX(dib) > 0) && (GetResolutionY(dib) > 0))
{
// SetResolution will throw an exception when zero values are given on input
result.SetResolution(GetResolutionX(dib), GetResolutionY(dib));
}
// Check whether the bitmap has a palette
if (GetPalette(dib) != IntPtr.Zero)
{
// Get the bitmaps palette to apply changes
ColorPalette palette = result.Palette;
// Get the orgininal palette
Color[] colorPalette = new Palette(dib).ColorData;
// Get the maximum number of palette entries to copy
int entriesToCopy = Math.Min(colorPalette.Length, palette.Entries.Length);
// Check whether the bitmap is transparent
if (IsTransparent(dib))
{
byte[] transTable = GetTransparencyTableEx(dib);
int i = 0;
int maxEntriesWithTrans = Math.Min(entriesToCopy, transTable.Length);
// Copy palette entries and include transparency
for (; i < maxEntriesWithTrans; i++)
{
palette.Entries[i] = Color.FromArgb(transTable[i], colorPalette[i]);
}
// Copy palette entries and that have no transparancy
for (; i < entriesToCopy; i++)
{
palette.Entries[i] = Color.FromArgb(0xFF, colorPalette[i]);
}
}
else
{
for (int i = 0; i < entriesToCopy; i++)
{
palette.Entries[i] = colorPalette[i];
}
}
// Set the bitmaps palette
result.Palette = palette;
}
// Copy metadata
if (copyMetadata)
{
try
{
List<PropertyItem> list = new List<PropertyItem>();
// Get a list of all types
FITAG tag;
FIMETADATA mData;
foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
{
// Get a unique search handle
mData = FindFirstMetadata(model, dib, out tag);
// Check if metadata exists for this type
if (mData.IsNull) continue;
do
{
PropertyItem propItem = CreatePropertyItem();
propItem.Len = (int)GetTagLength(tag);
propItem.Id = (int)GetTagID(tag);
propItem.Type = (short)GetTagType(tag);
byte[] buffer = new byte[propItem.Len];
unsafe
{
byte* src = (byte*)GetTagValue(tag);
fixed (byte* dst = buffer)
{
CopyMemory(dst, src, (uint)propItem.Len);
}
}
propItem.Value = buffer;
list.Add(propItem);
}
while (FindNextMetadata(mData, out tag));
FindCloseMetadata(mData);
}
foreach (PropertyItem propItem in list)
{
result.SetPropertyItem(propItem);
}
}
catch
{
}
}
return result;
}
/// <summary>
/// Converts an .NET <see cref="System.Drawing.Bitmap"/> into a FreeImage bitmap.
/// </summary>
/// <param name="bitmap">The <see cref="System.Drawing.Bitmap"/> to convert.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.</remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="bitmap"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The bitmaps pixelformat is invalid.</exception>
public static FIBITMAP CreateFromBitmap(Bitmap bitmap)
{
return CreateFromBitmap(bitmap, false);
}
/// <summary>
/// Converts an .NET <see cref="System.Drawing.Bitmap"/> into a FreeImage bitmap.
/// </summary>
/// <param name="bitmap">The <see cref="System.Drawing.Bitmap"/> to convert.</param>
/// <param name="copyMetadata">When true existing metadata will be copied.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.</remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="bitmap"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The bitmaps pixelformat is invalid.</exception>
internal static FIBITMAP CreateFromBitmap(Bitmap bitmap, bool copyMetadata)
{
if (bitmap == null)
{
throw new ArgumentNullException("bitmap");
}
uint bpp, red_mask, green_mask, blue_mask;
FREE_IMAGE_TYPE type;
if (!GetFormatParameters(bitmap.PixelFormat, out type, out bpp, out red_mask, out green_mask, out blue_mask))
{
throw new ArgumentException("The bitmaps pixelformat is invalid.");
}
// Locking the complete bitmap in readonly mode
BitmapData data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
// Copying the bitmap data directly from the .NET bitmap
FIBITMAP result = ConvertFromRawBits(
data.Scan0,
type,
data.Width,
data.Height,
data.Stride,
bpp,
red_mask,
green_mask,
blue_mask,
true);
bitmap.UnlockBits(data);
// Handle palette
if (GetPalette(result) != IntPtr.Zero)
{
Palette palette = new Palette(result);
Color[] colors = bitmap.Palette.Entries;
// Only copy available palette entries
int entriesToCopy = Math.Min(palette.Length, colors.Length);
byte[] transTable = new byte[entriesToCopy];
for (int i = 0; i < entriesToCopy; i++)
{
RGBQUAD color = (RGBQUAD)colors[i];
color.rgbReserved = 0x00;
palette[i] = color;
transTable[i] = colors[i].A;
}
if ((bitmap.Flags & (int)ImageFlags.HasAlpha) != 0)
{
FreeImage.SetTransparencyTable(result, transTable);
}
}
// Handle meta data
// Disabled
//if (copyMetadata)
//{
// foreach (PropertyItem propItem in bitmap.PropertyItems)
// {
// FITAG tag = CreateTag();
// SetTagLength(tag, (uint)propItem.Len);
// SetTagID(tag, (ushort)propItem.Id);
// SetTagType(tag, (FREE_IMAGE_MDTYPE)propItem.Type);
// SetTagValue(tag, propItem.Value);
// SetMetadata(FREE_IMAGE_MDMODEL.FIMD_EXIF_EXIF, result, "", tag);
// }
//}
return result;
}
/// <summary>
/// Converts a raw bitmap to a FreeImage bitmap.
/// </summary>
/// <param name="bits">Array of bytes containing the raw bitmap.</param>
/// <param name="type">The type of the raw bitmap.</param>
/// <param name="width">The width in pixels of the raw bitmap.</param>
/// <param name="height">The height in pixels of the raw bitmap.</param>
/// <param name="pitch">Defines the total width of a scanline in the raw bitmap,
/// including padding bytes.</param>
/// <param name="bpp">The bit depth (bits per pixel) of the raw bitmap.</param>
/// <param name="red_mask">The bit mask describing the bits used to store a single
/// pixel's red component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="green_mask">The bit mask describing the bits used to store a single
/// pixel's green component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="blue_mask">The bit mask describing the bits used to store a single
/// pixel's blue component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="topdown">If true, the raw bitmap is stored in top-down order (top-left pixel first)
/// and in bottom-up order (bottom-left pixel first) otherwise.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static unsafe FIBITMAP ConvertFromRawBits(
byte[] bits,
FREE_IMAGE_TYPE type,
int width,
int height,
int pitch,
uint bpp,
uint red_mask,
uint green_mask,
uint blue_mask,
bool topdown)
{
fixed (byte* ptr = bits)
{
return ConvertFromRawBits(
(IntPtr)ptr,
type,
width,
height,
pitch,
bpp,
red_mask,
green_mask,
blue_mask,
topdown);
}
}
/// <summary>
/// Converts a raw bitmap to a FreeImage bitmap.
/// </summary>
/// <param name="bits">Pointer to the memory block containing the raw bitmap.</param>
/// <param name="type">The type of the raw bitmap.</param>
/// <param name="width">The width in pixels of the raw bitmap.</param>
/// <param name="height">The height in pixels of the raw bitmap.</param>
/// <param name="pitch">Defines the total width of a scanline in the raw bitmap,
/// including padding bytes.</param>
/// <param name="bpp">The bit depth (bits per pixel) of the raw bitmap.</param>
/// <param name="red_mask">The bit mask describing the bits used to store a single
/// pixel's red component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="green_mask">The bit mask describing the bits used to store a single
/// pixel's green component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="blue_mask">The bit mask describing the bits used to store a single
/// pixel's blue component in the raw bitmap. This is only applied to 16-bpp raw bitmaps.</param>
/// <param name="topdown">If true, the raw bitmap is stored in top-down order (top-left pixel first)
/// and in bottom-up order (bottom-left pixel first) otherwise.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static unsafe FIBITMAP ConvertFromRawBits(
IntPtr bits,
FREE_IMAGE_TYPE type,
int width,
int height,
int pitch,
uint bpp,
uint red_mask,
uint green_mask,
uint blue_mask,
bool topdown)
{
byte* addr = (byte*)bits;
if ((addr == null) || (width <= 0) || (height <= 0))
{
return FIBITMAP.Zero;
}
FIBITMAP dib = AllocateT(type, width, height, (int)bpp, red_mask, green_mask, blue_mask);
if (dib != FIBITMAP.Zero)
{
if (topdown)
{
for (int i = height - 1; i >= 0; --i)
{
CopyMemory((byte*)GetScanLine(dib, i), addr, (int)GetLine(dib));
addr += pitch;
}
}
else
{
for (int i = 0; i < height; ++i)
{
CopyMemory((byte*)GetScanLine(dib, i), addr, (int)GetLine(dib));
addr += pitch;
}
}
}
return dib;
}
/// <summary>
/// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
/// </summary>
/// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
/// <param name="filename">Name of the file to save to.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The bitmaps pixelformat is invalid.</exception>
public static bool SaveBitmap(Bitmap bitmap, string filename)
{
return SaveBitmap(
bitmap,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
FREE_IMAGE_SAVE_FLAGS.DEFAULT);
}
/// <summary>
/// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
/// </summary>
/// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
/// <param name="filename">Name of the file to save to.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The bitmaps pixelformat is invalid.</exception>
public static bool SaveBitmap(Bitmap bitmap, string filename, FREE_IMAGE_SAVE_FLAGS flags)
{
return SaveBitmap(
bitmap,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
flags);
}
/// <summary>
/// Saves a .NET <see cref="System.Drawing.Bitmap"/> to a file.
/// </summary>
/// <param name="bitmap">The .NET <see cref="System.Drawing.Bitmap"/> to save.</param>
/// <param name="filename">Name of the file to save to.</param>
/// <param name="format">Format of the bitmap. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="bitmap"/> or <paramref name="filename"/> is null.</exception>
/// <exception cref="ArgumentException">
/// The bitmaps pixelformat is invalid.</exception>
public static bool SaveBitmap(
Bitmap bitmap,
string filename,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags)
{
FIBITMAP dib = CreateFromBitmap(bitmap);
bool result = SaveEx(dib, filename, format, flags);
Unload(dib);
return result;
}
/// <summary>
/// Loads a FreeImage bitmap.
/// The file will be loaded with default loading flags.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists.</exception>
public static FIBITMAP LoadEx(string filename)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// Load flags can be provided by the flags parameter.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists.</exception>
public static FIBITMAP LoadEx(string filename, FREE_IMAGE_LOAD_FLAGS flags)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return LoadEx(filename, flags, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
/// real format is being analysed. If no plugin can read the file, format remains
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
/// The file will be loaded with default loading flags.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadEx it will be returned in format.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists.</exception>
public static FIBITMAP LoadEx(string filename, ref FREE_IMAGE_FORMAT format)
{
return LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
/// real format is being analysed. If no plugin can read the file, format remains
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
/// Load flags can be provided by the flags parameter.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadEx it will be returned in format.
/// </param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists.</exception>
public static FIBITMAP LoadEx(string filename, FREE_IMAGE_LOAD_FLAGS flags, ref FREE_IMAGE_FORMAT format)
{
// check if file exists
if (!File.Exists(filename))
{
throw new FileNotFoundException(filename + " could not be found.");
}
FIBITMAP dib = new FIBITMAP();
if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
// query all plugins to see if one can read the file
format = GetFileType(filename, 0);
}
// check if the plugin is capable of loading files
if (FIFSupportsReading(format))
{
dib = Load(format, filename, flags);
}
return dib;
}
/// <summary>
/// Loads a .NET <see cref="System.Drawing.Bitmap"/> from a file.
/// </summary>
/// <param name="filename">Name of the file to be loaded.</param>
/// <param name="format">Format of the image. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>The loaded .NET <see cref="System.Drawing.Bitmap"/>.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists.</exception>
/// <exception cref="ArgumentException">
/// The image type of the image is not <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/>.</exception>
public static Bitmap LoadBitmap(string filename, FREE_IMAGE_LOAD_FLAGS flags, ref FREE_IMAGE_FORMAT format)
{
FIBITMAP dib = LoadEx(filename, flags, ref format);
Bitmap result = GetBitmap(dib, true);
Unload(dib);
return result;
}
/// <summary>
/// Deletes a previously loaded FreeImage bitmap from memory and resets the handle to 0.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
public static void UnloadEx(ref FIBITMAP dib)
{
if (!dib.IsNull)
{
Unload(dib);
dib.SetNull();
}
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// The format is taken off the filename.
/// If no suitable format was found false will be returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(FIBITMAP dib, string filename)
{
return SaveEx(
ref dib,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="format">Format of the image. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
FIBITMAP dib,
string filename,
FREE_IMAGE_FORMAT format)
{
return SaveEx(
ref dib,
filename,
format,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// The format is taken off the filename.
/// If no suitable format was found false will be returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
ref FIBITMAP dib,
string filename,
bool unloadSource)
{
return SaveEx(
ref dib,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
unloadSource);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// The format is taken off the filename.
/// If no suitable format was found false will be returned.
/// Save flags can be provided by the flags parameter.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
FIBITMAP dib,
string filename,
FREE_IMAGE_SAVE_FLAGS flags)
{
return SaveEx(
ref dib,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
flags,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// The format is taken off the filename.
/// If no suitable format was found false will be returned.
/// Save flags can be provided by the flags parameter.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
ref FIBITMAP dib,
string filename,
FREE_IMAGE_SAVE_FLAGS flags,
bool unloadSource)
{
return SaveEx(
ref dib,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
flags,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
unloadSource);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="format">Format of the image. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
ref FIBITMAP dib,
string filename,
FREE_IMAGE_FORMAT format,
bool unloadSource)
{
return SaveEx(
ref dib,
filename,
format,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
unloadSource);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
/// Save flags can be provided by the flags parameter.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="format">Format of the image. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
FIBITMAP dib,
string filename,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags)
{
return SaveEx(
ref dib,
filename,
format,
flags,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
/// Save flags can be provided by the flags parameter.
/// The bitmaps color depth can be set by 'colorDepth'.
/// If set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> a suitable color depth
/// will be taken if available.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="filename">The complete name of the file to save to.
/// The extension will be corrected if it is no valid extension for the
/// selected format or if no extension was specified.</param>
/// <param name="format">Format of the image. If the format should be taken from the
/// filename use <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="colorDepth">The new color depth of the bitmap.
/// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if Save should take the
/// best suitable color depth.
/// If a color depth is selected that the provided format cannot write an
/// error-message will be thrown.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentException">
/// A direct color conversion failed.</exception>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="filename"/> is null.</exception>
public static bool SaveEx(
ref FIBITMAP dib,
string filename,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags,
FREE_IMAGE_COLOR_DEPTH colorDepth,
bool unloadSource)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
if (filename == null)
{
throw new ArgumentNullException("filename");
}
bool result = false;
// Gets format from filename if the format is unknown
if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
format = GetFIFFromFilename(filename);
}
if (format != FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
// Checks writing support
if (FIFSupportsWriting(format) && FIFSupportsExportType(format, GetImageType(dib)))
{
// Check valid filename and correct it if needed
if (!IsFilenameValidForFIF(format, filename))
{
string extension = GetPrimaryExtensionFromFIF(format);
filename = Path.ChangeExtension(filename, extension);
}
FIBITMAP dibToSave = PrepareBitmapColorDepth(dib, format, colorDepth);
try
{
result = Save(format, dibToSave, filename, flags);
}
finally
{
// Always unload a temporary created bitmap.
if (dibToSave != dib)
{
UnloadEx(ref dibToSave);
}
// On success unload the bitmap
if (result && unloadSource)
{
UnloadEx(ref dib);
}
}
}
}
return result;
}
/// <summary>
/// Loads a FreeImage bitmap.
/// The stream must be set to the correct position before calling LoadFromStream.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> is not capable of reading.</exception>
public static FIBITMAP LoadFromStream(Stream stream)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return LoadFromStream(stream, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// The stream must be set to the correct position before calling LoadFromStream.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> is not capable of reading.</exception>
public static FIBITMAP LoadFromStream(Stream stream, FREE_IMAGE_LOAD_FLAGS flags)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return LoadFromStream(stream, flags, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the
/// bitmaps real format is being analysed.
/// The stream must be set to the correct position before calling LoadFromStream.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadFromStream it will be returned in format.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> is not capable of reading.</exception>
public static FIBITMAP LoadFromStream(Stream stream, ref FREE_IMAGE_FORMAT format)
{
return LoadFromStream(stream, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
/// <summary>
/// Loads a FreeImage bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>
/// the bitmaps real format is being analysed.
/// The stream must be set to the correct position before calling LoadFromStream.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadFromStream it will be returned in format.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> is not capable of reading.</exception>
public static FIBITMAP LoadFromStream(
Stream stream,
FREE_IMAGE_LOAD_FLAGS flags,
ref FREE_IMAGE_FORMAT format)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
throw new ArgumentException("stream is not capable of reading.");
}
// Wrap the source stream if it is unable to seek (which is required by FreeImage)
stream = (stream.CanSeek) ? stream : new StreamWrapper(stream, true);
stream.Position = 0L;
if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
// Get the format of the bitmap
format = GetFileTypeFromStream(stream);
// Restore the streams position
stream.Position = 0L;
}
if (!FIFSupportsReading(format))
{
return FIBITMAP.Zero;
}
// Create a 'FreeImageIO' structure for calling 'LoadFromHandle'
// using the internal structure 'FreeImageStreamIO'.
FreeImageIO io = FreeImageStreamIO.io;
using (fi_handle handle = new fi_handle(stream))
{
return LoadFromHandle(format, ref io, handle, flags);
}
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format)
{
return SaveToStream(
ref dib,
stream,
format,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
ref FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format,
bool unloadSource)
{
return SaveToStream(
ref dib,
stream,
format,
FREE_IMAGE_SAVE_FLAGS.DEFAULT,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
unloadSource);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags)
{
return SaveToStream(
ref dib,
stream,
format,
flags,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
ref FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags,
bool unloadSource)
{
return SaveToStream(
ref dib, stream,
format,
flags,
FREE_IMAGE_COLOR_DEPTH.FICD_AUTO,
unloadSource);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="colorDepth">The new color depth of the bitmap.
/// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if SaveToStream should
/// take the best suitable color depth.
/// If a color depth is selected that the provided format cannot write an
/// error-message will be thrown.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags,
FREE_IMAGE_COLOR_DEPTH colorDepth)
{
return SaveToStream(
ref dib,
stream,
format,
flags,
colorDepth,
false);
}
/// <summary>
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="format">Format of the image.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="colorDepth">The new color depth of the bitmap.
/// Set to <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_AUTO"/> if SaveToStream should
/// take the best suitable color depth.
/// If a color depth is selected that the provided format cannot write an
/// error-message will be thrown.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> cannot write.</exception>
public static bool SaveToStream(
ref FIBITMAP dib,
Stream stream,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_SAVE_FLAGS flags,
FREE_IMAGE_COLOR_DEPTH colorDepth,
bool unloadSource)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanWrite)
{
throw new ArgumentException("stream is not capable of writing.");
}
if ((!FIFSupportsWriting(format)) || (!FIFSupportsExportType(format, GetImageType(dib))))
{
return false;
}
FIBITMAP dibToSave = PrepareBitmapColorDepth(dib, format, colorDepth);
bool result = false;
try
{
// Create a 'FreeImageIO' structure for calling 'SaveToHandle'
FreeImageIO io = FreeImageStreamIO.io;
using (fi_handle handle = new fi_handle(stream))
{
result = SaveToHandle(format, dibToSave, ref io, handle, flags);
}
}
finally
{
// Always unload a temporary created bitmap.
if (dibToSave != dib)
{
UnloadEx(ref dibToSave);
}
// On success unload the bitmap
if (result && unloadSource)
{
UnloadEx(ref dib);
}
}
return result;
}
#endregion
#region Plugin functions
/// <summary>
/// Checks if an extension is valid for a certain format.
/// </summary>
/// <param name="fif">The desired format.</param>
/// <param name="extension">The desired extension.</param>
/// <returns>True if the extension is valid for the given format, false otherwise.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="extension"/> is null.</exception>
public static bool IsExtensionValidForFIF(FREE_IMAGE_FORMAT fif, string extension)
{
return IsExtensionValidForFIF(fif, extension, StringComparison.CurrentCultureIgnoreCase);
}
/// <summary>
/// Checks if an extension is valid for a certain format.
/// </summary>
/// <param name="fif">The desired format.</param>
/// <param name="extension">The desired extension.</param>
/// <param name="comparisonType">The string comparison type.</param>
/// <returns>True if the extension is valid for the given format, false otherwise.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="extension"/> is null.</exception>
public static bool IsExtensionValidForFIF(FREE_IMAGE_FORMAT fif, string extension, StringComparison comparisonType)
{
if (extension == null)
{
throw new ArgumentNullException("extension");
}
bool result = false;
// Split up the string and compare each with the given extension
string tempList = GetFIFExtensionList(fif);
if (tempList != null)
{
string[] extensionList = tempList.Split(',');
foreach (string ext in extensionList)
{
if (extension.Equals(ext, comparisonType))
{
result = true;
break;
}
}
}
return result;
}
/// <summary>
/// Checks if a filename is valid for a certain format.
/// </summary>
/// <param name="fif">The desired format.</param>
/// <param name="filename">The desired filename.</param>
/// <returns>True if the filename is valid for the given format, false otherwise.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filename"/> is null.</exception>
public static bool IsFilenameValidForFIF(FREE_IMAGE_FORMAT fif, string filename)
{
return IsFilenameValidForFIF(fif, filename, StringComparison.CurrentCultureIgnoreCase);
}
/// <summary>
/// Checks if a filename is valid for a certain format.
/// </summary>
/// <param name="fif">The desired format.</param>
/// <param name="filename">The desired filename.</param>
/// <param name="comparisonType">The string comparison type.</param>
/// <returns>True if the filename is valid for the given format, false otherwise.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="filename"/> is null.</exception>
public static bool IsFilenameValidForFIF(FREE_IMAGE_FORMAT fif, string filename, StringComparison comparisonType)
{
if (filename == null)
{
throw new ArgumentNullException("filename");
}
bool result = false;
// Extract the filenames extension if it exists
string extension = Path.GetExtension(filename);
if (extension.Length != 0)
{
extension = extension.Remove(0, 1);
result = IsExtensionValidForFIF(fif, extension, comparisonType);
}
return result;
}
/// <summary>
/// This function returns the primary (main or most commonly used?) extension of a certain
/// image format (fif). This is done by returning the first of all possible extensions
/// returned by GetFIFExtensionList().
/// That assumes, that the plugin returns the extensions in ordered form.</summary>
/// <param name="fif">The image format to obtain the primary extension for.</param>
/// <returns>The primary extension of the specified image format.</returns>
public static string GetPrimaryExtensionFromFIF(FREE_IMAGE_FORMAT fif)
{
string result = null;
string extensions = GetFIFExtensionList(fif);
if (extensions != null)
{
int position = extensions.IndexOf(',');
if (position < 0)
{
result = extensions;
}
else
{
result = extensions.Substring(0, position);
}
}
return result;
}
#endregion
#region Multipage functions
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(string filename)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return OpenMultiBitmapEx(
filename,
ref format,
FREE_IMAGE_LOAD_FLAGS.DEFAULT,
false,
false,
false);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(string filename, bool keep_cache_in_memory)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return OpenMultiBitmapEx(
filename,
ref format,
FREE_IMAGE_LOAD_FLAGS.DEFAULT,
false,
false,
keep_cache_in_memory);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="read_only">When true the bitmap will be loaded read only.</param>
/// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(
string filename,
bool read_only,
bool keep_cache_in_memory)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return OpenMultiBitmapEx(
filename,
ref format,
FREE_IMAGE_LOAD_FLAGS.DEFAULT,
false,
read_only,
keep_cache_in_memory);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="create_new">When true a new bitmap is created.</param>
/// <param name="read_only">When true the bitmap will be loaded read only.</param>
/// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(
string filename,
bool create_new,
bool read_only,
bool keep_cache_in_memory)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return OpenMultiBitmapEx(
filename,
ref format,
FREE_IMAGE_LOAD_FLAGS.DEFAULT,
create_new,
read_only,
keep_cache_in_memory);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files real
/// format is being analysed. If no plugin can read the file, format remains
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadEx it will be returned in format.</param>
/// <param name="create_new">When true a new bitmap is created.</param>
/// <param name="read_only">When true the bitmap will be loaded read only.</param>
/// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(
string filename,
ref FREE_IMAGE_FORMAT format,
bool create_new,
bool read_only,
bool keep_cache_in_memory)
{
return OpenMultiBitmapEx(
filename,
ref format,
FREE_IMAGE_LOAD_FLAGS.DEFAULT,
create_new,
read_only,
keep_cache_in_memory);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
/// real format is being analysed. If no plugin can read the file, format remains
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
/// Load flags can be provided by the flags parameter.
/// </summary>
/// <param name="filename">The complete name of the file to load.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/>.
/// In case a suitable format was found by LoadEx it will be returned in format.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="create_new">When true a new bitmap is created.</param>
/// <param name="read_only">When true the bitmap will be loaded read only.</param>
/// <param name="keep_cache_in_memory">When true performance is increased at the cost of memory.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="FileNotFoundException">
/// <paramref name="filename"/> does not exists while opening.</exception>
public static FIMULTIBITMAP OpenMultiBitmapEx(
string filename,
ref FREE_IMAGE_FORMAT format,
FREE_IMAGE_LOAD_FLAGS flags,
bool create_new,
bool read_only,
bool keep_cache_in_memory)
{
if (!File.Exists(filename) && !create_new)
{
throw new FileNotFoundException(filename + " could not be found.");
}
if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
// Check if a plugin can read the data
format = GetFileType(filename, 0);
}
FIMULTIBITMAP dib = new FIMULTIBITMAP();
if (FIFSupportsReading(format))
{
dib = OpenMultiBitmap(format, filename, create_new, read_only, keep_cache_in_memory, flags);
}
return dib;
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// </summary>
/// <param name="stream">The stream to load the bitmap from.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
public static FIMULTIBITMAP OpenMultiBitmapFromStream(Stream stream)
{
FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
return OpenMultiBitmapFromStream(stream, ref format, FREE_IMAGE_LOAD_FLAGS.DEFAULT);
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> the files
/// real format is being analysed. If no plugin can read the file, format remains
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/> and 0 is returned.
/// Load flags can be provided by the flags parameter.
/// </summary>
/// <param name="stream">The stream to load the bitmap from.</param>
/// <param name="format">Format of the image. If the format is unknown use
/// <see cref="FREE_IMAGE_FORMAT.FIF_UNKNOWN"/></param>.
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
public static FIMULTIBITMAP OpenMultiBitmapFromStream(Stream stream, ref FREE_IMAGE_FORMAT format, FREE_IMAGE_LOAD_FLAGS flags)
{
if (stream == null)
return FIMULTIBITMAP.Zero;
if (!stream.CanSeek)
stream = new StreamWrapper(stream, true);
FIMULTIBITMAP mdib = FIMULTIBITMAP.Zero;
FreeImageIO io = FreeImageStreamIO.io;
fi_handle handle = new fi_handle(stream);
try
{
if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
{
format = GetFileTypeFromHandle(ref io, handle, checked((int)stream.Length));
}
mdib = OpenMultiBitmapFromHandle(format, ref io, handle, flags);
if (mdib.IsNull)
{
handle.Dispose();
}
else
{
lock (streamHandles)
{
streamHandles.Add(mdib, handle);
}
}
return mdib;
}
catch
{
if (!mdib.IsNull)
CloseMultiBitmap(mdib, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
if (handle != null)
handle.Dispose();
throw;
}
}
/// <summary>
/// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only, applies any changes made to it.
/// </summary>
/// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
public static bool CloseMultiBitmap(FIMULTIBITMAP bitmap, FREE_IMAGE_SAVE_FLAGS flags)
{
if (CloseMultiBitmap_(bitmap, flags))
{
fi_handle handle;
lock (streamHandles)
{
if (streamHandles.TryGetValue(bitmap, out handle))
{
streamHandles.Remove(bitmap);
handle.Dispose();
}
}
return true;
}
return false;
}
/// <summary>
/// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only,
/// applies any changes made to it.
/// On success the handle will be reset to null.
/// </summary>
/// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
/// <returns>Returns true on success, false on failure.</returns>
public static bool CloseMultiBitmapEx(ref FIMULTIBITMAP bitmap)
{
return CloseMultiBitmapEx(ref bitmap, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
}
/// <summary>
/// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only,
/// applies any changes made to it.
/// On success the handle will be reset to null.
/// </summary>
/// <param name="bitmap">Handle to a FreeImage multi-paged bitmap.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <returns>Returns true on success, false on failure.</returns>
public static bool CloseMultiBitmapEx(ref FIMULTIBITMAP bitmap, FREE_IMAGE_SAVE_FLAGS flags)
{
bool result = false;
if (!bitmap.IsNull)
{
if (CloseMultiBitmap(bitmap, flags))
{
bitmap.SetNull();
result = true;
}
}
return result;
}
/// <summary>
/// Retrieves the number of pages that are locked in a multi-paged bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage multi-paged bitmap.</param>
/// <returns>Number of locked pages.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static int GetLockedPageCount(FIMULTIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
int result = 0;
GetLockedPageNumbers(dib, null, ref result);
return result;
}
/// <summary>
/// Retrieves a list locked pages of a multi-paged bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage multi-paged bitmap.</param>
/// <returns>List containing the indexes of the locked pages.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static int[] GetLockedPages(FIMULTIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
// Get the number of pages and create an array to save the information
int count = 0;
int[] result = null;
// Get count
if (GetLockedPageNumbers(dib, result, ref count))
{
result = new int[count];
// Fill array
if (!GetLockedPageNumbers(dib, result, ref count))
{
result = null;
}
}
return result;
}
/// <summary>
/// Loads a FreeImage multi-paged bitmap from a stream and returns the
/// FreeImage memory stream used as temporary buffer.
/// The bitmap can not be modified by calling
/// <see cref="FreeImage.AppendPage(FIMULTIBITMAP,FIBITMAP)"/>,
/// <see cref="FreeImage.InsertPage(FIMULTIBITMAP,Int32,FIBITMAP)"/>,
/// <see cref="FreeImage.MovePage(FIMULTIBITMAP,Int32,Int32)"/> or
/// <see cref="FreeImage.DeletePage(FIMULTIBITMAP,Int32)"/>.
/// </summary>
/// <param name="stream">The stream to read from.</param>
/// <param name="format">Format of the image.</param>
/// <param name="flags">Flags to enable or disable plugin-features.</param>
/// <param name="memory">The temporary memory buffer used to load the bitmap.</param>
/// <returns>Handle to a FreeImage multi-paged bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> can not read.</exception>
public static FIMULTIBITMAP LoadMultiBitmapFromStream(
Stream stream,
FREE_IMAGE_FORMAT format,
FREE_IMAGE_LOAD_FLAGS flags,
out FIMEMORY memory)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
throw new ArgumentException("stream");
}
const int blockSize = 1024;
int bytesRead;
byte[] buffer = new byte[blockSize];
stream = stream.CanSeek ? stream : new StreamWrapper(stream, true);
memory = OpenMemory(IntPtr.Zero, 0);
do
{
bytesRead = stream.Read(buffer, 0, blockSize);
WriteMemory(buffer, (uint)blockSize, (uint)1, memory);
}
while (bytesRead == blockSize);
return LoadMultiBitmapFromMemory(format, memory, flags);
}
#endregion
#region Filetype functions
/// <summary>
/// Orders FreeImage to analyze the bitmap signature.
/// In case the stream is not seekable, the stream will have been used
/// and must be recreated for loading.
/// </summary>
/// <param name="stream">Name of the stream to analyze.</param>
/// <returns>Type of the bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException">
/// <paramref name="stream"/> can not read.</exception>
public static FREE_IMAGE_FORMAT GetFileTypeFromStream(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (!stream.CanRead)
{
throw new ArgumentException("stream is not capable of reading.");
}
// Wrap the stream if it cannot seek
stream = (stream.CanSeek) ? stream : new StreamWrapper(stream, true);
// Create a 'FreeImageIO' structure for the stream
FreeImageIO io = FreeImageStreamIO.io;
using (fi_handle handle = new fi_handle(stream))
{
return GetFileTypeFromHandle(ref io, handle, 0);
}
}
#endregion
#region Pixel access functions
/// <summary>
/// Retrieves an hBitmap for a FreeImage bitmap.
/// Call FreeHbitmap(IntPtr) to free the handle.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="hdc">A reference device context.
/// Use IntPtr.Zero if no reference is available.</param>
/// <param name="unload">When true dib will be unloaded if the function succeeded.</param>
/// <returns>The hBitmap for the FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe IntPtr GetHbitmap(FIBITMAP dib, IntPtr hdc, bool unload)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
IntPtr hBitmap = IntPtr.Zero;
bool release = false;
IntPtr ppvBits = IntPtr.Zero;
// Check if we have destination
if (release = (hdc == IntPtr.Zero))
{
// We don't so request dc
hdc = GetDC(IntPtr.Zero);
}
if (hdc != IntPtr.Zero)
{
// Get pointer to the infoheader of the bitmap
IntPtr info = GetInfo(dib);
// Create a bitmap in the dc
hBitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0);
if (hBitmap != IntPtr.Zero && ppvBits != IntPtr.Zero)
{
// Copy the data into the dc
CopyMemory(ppvBits, GetBits(dib), (GetHeight(dib) * GetPitch(dib)));
// Success: we unload the bitmap
if (unload)
{
Unload(dib);
}
}
// We have to release the dc
if (release)
{
ReleaseDC(IntPtr.Zero, hdc);
}
}
return hBitmap;
}
/// <summary>
/// Returns an HBITMAP created by the <c>CreateDIBitmap()</c> function which in turn
/// has always the same color depth as the reference DC, which may be provided
/// through <paramref name="hdc"/>. The desktop DC will be used,
/// if <c>IntPtr.Zero</c> DC is specified.
/// Call <see cref="FreeImage.FreeHbitmap(IntPtr)"/> to free the handle.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="hdc">Handle to a device context.</param>
/// <param name="unload">When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.</param>
/// <returns>If the function succeeds, the return value is a handle to the
/// compatible bitmap. If the function fails, the return value is <see cref="IntPtr.Zero"/>.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static IntPtr GetBitmapForDevice(FIBITMAP dib, IntPtr hdc, bool unload)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
IntPtr hbitmap = IntPtr.Zero;
bool release = false;
if (release = (hdc == IntPtr.Zero))
{
hdc = GetDC(IntPtr.Zero);
}
if (hdc != IntPtr.Zero)
{
hbitmap = CreateDIBitmap(
hdc,
GetInfoHeader(dib),
CBM_INIT,
GetBits(dib),
GetInfo(dib),
DIB_RGB_COLORS);
if (unload)
{
Unload(dib);
}
if (release)
{
ReleaseDC(IntPtr.Zero, hdc);
}
}
return hbitmap;
}
/// <summary>
/// Creates a FreeImage DIB from a Device Context/Compatible Bitmap.
/// </summary>
/// <param name="hbitmap">Handle to the bitmap.</param>
/// <param name="hdc">Handle to a device context.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="hbitmap"/> is null.</exception>
public unsafe static FIBITMAP CreateFromHbitmap(IntPtr hbitmap, IntPtr hdc)
{
if (hbitmap == IntPtr.Zero)
{
throw new ArgumentNullException("hbitmap");
}
FIBITMAP dib = new FIBITMAP();
BITMAP bm;
uint colors;
bool release;
if (GetObject(hbitmap, sizeof(BITMAP), (IntPtr)(&bm)) != 0)
{
dib = Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0, 0, 0);
if (!dib.IsNull)
{
colors = GetColorsUsed(dib);
if (release = (hdc == IntPtr.Zero))
{
hdc = GetDC(IntPtr.Zero);
}
if (GetDIBits(
hdc,
hbitmap,
0,
(uint)bm.bmHeight,
GetBits(dib),
GetInfo(dib),
DIB_RGB_COLORS) != 0)
{
if (colors != 0)
{
BITMAPINFOHEADER* bmih = (BITMAPINFOHEADER*)GetInfo(dib);
bmih[0].biClrImportant = bmih[0].biClrUsed = colors;
}
}
else
{
UnloadEx(ref dib);
}
if (release)
{
ReleaseDC(IntPtr.Zero, hdc);
}
}
}
return dib;
}
/// <summary>
/// Frees a bitmap handle.
/// </summary>
/// <param name="hbitmap">Handle to a bitmap.</param>
/// <returns>True on success, false on failure.</returns>
public static bool FreeHbitmap(IntPtr hbitmap)
{
return DeleteObject(hbitmap);
}
#endregion
#region Bitmap information functions
/// <summary>
/// Retrieves a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>The resolution in 'dots per inch'.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static uint GetResolutionX(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return (uint)(0.5d + 0.0254d * GetDotsPerMeterX(dib));
}
/// <summary>
/// Retrieves a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>The resolution in 'dots per inch'.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static uint GetResolutionY(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return (uint)(0.5d + 0.0254d * GetDotsPerMeterY(dib));
}
/// <summary>
/// Sets a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="res">The new resolution in 'dots per inch'.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static void SetResolutionX(FIBITMAP dib, uint res)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
SetDotsPerMeterX(dib, (uint)((double)res / 0.0254d + 0.5d));
}
/// <summary>
/// Sets a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="res">The new resolution in 'dots per inch'.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static void SetResolutionY(FIBITMAP dib, uint res)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
SetDotsPerMeterY(dib, (uint)((double)res / 0.0254d + 0.5d));
}
/// <summary>
/// Returns whether the image is a greyscale image or not.
/// The function scans all colors in the bitmaps palette for entries where
/// red, green and blue are not all the same (not a grey color).
/// Supports 1-, 4- and 8-bit bitmaps.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>True if the image is a greyscale image, else false.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe bool IsGreyscaleImage(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
bool result = true;
uint bpp = GetBPP(dib);
switch (bpp)
{
case 1:
case 4:
case 8:
RGBQUAD* palette = (RGBQUAD*)GetPalette(dib);
uint paletteLength = GetColorsUsed(dib);
for (int i = 0; i < paletteLength; i++)
{
if (palette[i].rgbRed != palette[i].rgbGreen ||
palette[i].rgbRed != palette[i].rgbBlue)
{
result = false;
break;
}
}
break;
default:
result = false;
break;
}
return result;
}
/// <summary>
/// Returns a structure that represents the palette of a FreeImage bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>A structure representing the bitmaps palette.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static Palette GetPaletteEx(FIBITMAP dib)
{
return new Palette(dib);
}
/// <summary>
/// Returns the <see cref="BITMAPINFOHEADER"/> structure of a FreeImage bitmap.
/// The structure is a copy, so changes will have no effect on
/// the bitmap itself.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns><see cref="BITMAPINFOHEADER"/> structure of the bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe BITMAPINFOHEADER GetInfoHeaderEx(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return *(BITMAPINFOHEADER*)GetInfoHeader(dib);
}
/// <summary>
/// Returns the <see cref="BITMAPINFO"/> structure of a FreeImage bitmap.
/// The structure is a copy, so changes will have no effect on
/// the bitmap itself.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns><see cref="BITMAPINFO"/> structure of the bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static BITMAPINFO GetInfoEx(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
BITMAPINFO result = new BITMAPINFO();
result.bmiHeader = GetInfoHeaderEx(dib);
IntPtr ptr = GetPalette(dib);
if (ptr == IntPtr.Zero)
{
result.bmiColors = new RGBQUAD[0];
}
else
{
result.bmiColors = new MemoryArray<RGBQUAD>(ptr, (int)result.bmiHeader.biClrUsed).Data;
}
return result;
}
/// <summary>
/// Returns the pixelformat of the bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns><see cref="System.Drawing.Imaging.PixelFormat"/> of the bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static PixelFormat GetPixelFormat(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
PixelFormat result = PixelFormat.Undefined;
if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
{
switch (GetBPP(dib))
{
case 1:
result = PixelFormat.Format1bppIndexed;
break;
case 4:
result = PixelFormat.Format4bppIndexed;
break;
case 8:
result = PixelFormat.Format8bppIndexed;
break;
case 16:
if ((GetBlueMask(dib) == FI16_565_BLUE_MASK) &&
(GetGreenMask(dib) == FI16_565_GREEN_MASK) &&
(GetRedMask(dib) == FI16_565_RED_MASK))
{
result = PixelFormat.Format16bppRgb565;
}
if ((GetBlueMask(dib) == FI16_555_BLUE_MASK) &&
(GetGreenMask(dib) == FI16_555_GREEN_MASK) &&
(GetRedMask(dib) == FI16_555_RED_MASK))
{
result = PixelFormat.Format16bppRgb555;
}
break;
case 24:
result = PixelFormat.Format24bppRgb;
break;
case 32:
result = PixelFormat.Format32bppArgb;
break;
}
}
return result;
}
/// <summary>
/// Retrieves all parameters needed to create a new FreeImage bitmap from
/// the format of a .NET <see cref="System.Drawing.Image"/>.
/// </summary>
/// <param name="format">The <see cref="System.Drawing.Imaging.PixelFormat"/>
/// of the .NET <see cref="System.Drawing.Image"/>.</param>
/// <param name="type">Returns the type used for the new bitmap.</param>
/// <param name="bpp">Returns the color depth for the new bitmap.</param>
/// <param name="red_mask">Returns the red_mask for the new bitmap.</param>
/// <param name="green_mask">Returns the green_mask for the new bitmap.</param>
/// <param name="blue_mask">Returns the blue_mask for the new bitmap.</param>
/// <returns>True in case a matching conversion exists; else false.
/// </returns>
public static bool GetFormatParameters(
PixelFormat format,
out FREE_IMAGE_TYPE type,
out uint bpp,
out uint red_mask,
out uint green_mask,
out uint blue_mask)
{
bool result = false;
type = FREE_IMAGE_TYPE.FIT_UNKNOWN;
bpp = 0;
red_mask = 0;
green_mask = 0;
blue_mask = 0;
switch (format)
{
case PixelFormat.Format1bppIndexed:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 1;
result = true;
break;
case PixelFormat.Format4bppIndexed:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 4;
result = true;
break;
case PixelFormat.Format8bppIndexed:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 8;
result = true;
break;
case PixelFormat.Format16bppRgb565:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 16;
red_mask = FI16_565_RED_MASK;
green_mask = FI16_565_GREEN_MASK;
blue_mask = FI16_565_BLUE_MASK;
result = true;
break;
case PixelFormat.Format16bppRgb555:
case PixelFormat.Format16bppArgb1555:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 16;
red_mask = FI16_555_RED_MASK;
green_mask = FI16_555_GREEN_MASK;
blue_mask = FI16_555_BLUE_MASK;
result = true;
break;
case PixelFormat.Format24bppRgb:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 24;
red_mask = FI_RGBA_RED_MASK;
green_mask = FI_RGBA_GREEN_MASK;
blue_mask = FI_RGBA_BLUE_MASK;
result = true;
break;
case PixelFormat.Format32bppRgb:
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
type = FREE_IMAGE_TYPE.FIT_BITMAP;
bpp = 32;
red_mask = FI_RGBA_RED_MASK;
green_mask = FI_RGBA_GREEN_MASK;
blue_mask = FI_RGBA_BLUE_MASK;
result = true;
break;
case PixelFormat.Format16bppGrayScale:
type = FREE_IMAGE_TYPE.FIT_UINT16;
bpp = 16;
result = true;
break;
case PixelFormat.Format48bppRgb:
type = FREE_IMAGE_TYPE.FIT_RGB16;
bpp = 48;
result = true;
break;
case PixelFormat.Format64bppArgb:
case PixelFormat.Format64bppPArgb:
type = FREE_IMAGE_TYPE.FIT_RGBA16;
bpp = 64;
result = true;
break;
}
return result;
}
/// <summary>
/// Returns the <see cref="FREE_IMAGE_FORMAT"/> for the specified
/// <see cref="ImageFormat"/>.
/// </summary>
/// <param name="imageFormat">The <see cref="ImageFormat"/>
/// for which to return the corresponding <see cref="FREE_IMAGE_FORMAT"/>.</param>
/// <returns>The <see cref="FREE_IMAGE_FORMAT"/> for the specified
/// <see cref="ImageFormat"/></returns>
public static FREE_IMAGE_FORMAT GetFormat(ImageFormat imageFormat)
{
if (imageFormat != null)
{
if (imageFormat.Equals(ImageFormat.Bmp))
return FREE_IMAGE_FORMAT.FIF_BMP;
if (imageFormat.Equals(ImageFormat.Gif))
return FREE_IMAGE_FORMAT.FIF_GIF;
if (imageFormat.Equals(ImageFormat.Icon))
return FREE_IMAGE_FORMAT.FIF_ICO;
if (imageFormat.Equals(ImageFormat.Jpeg))
return FREE_IMAGE_FORMAT.FIF_JPEG;
if (imageFormat.Equals(ImageFormat.Png))
return FREE_IMAGE_FORMAT.FIF_PNG;
if (imageFormat.Equals(ImageFormat.Tiff))
return FREE_IMAGE_FORMAT.FIF_TIFF;
}
return FREE_IMAGE_FORMAT.FIF_UNKNOWN;
}
/// <summary>
/// Retrieves all parameters needed to create a new FreeImage bitmap from
/// raw bits <see cref="System.Drawing.Image"/>.
/// </summary>
/// <param name="type">The <see cref="FREE_IMAGE_TYPE"/>
/// of the data in memory.</param>
/// <param name="bpp">The color depth for the data.</param>
/// <param name="red_mask">Returns the red_mask for the data.</param>
/// <param name="green_mask">Returns the green_mask for the data.</param>
/// <param name="blue_mask">Returns the blue_mask for the data.</param>
/// <returns>True in case a matching conversion exists; else false.
/// </returns>
public static bool GetTypeParameters(
FREE_IMAGE_TYPE type,
int bpp,
out uint red_mask,
out uint green_mask,
out uint blue_mask)
{
bool result = false;
red_mask = 0;
green_mask = 0;
blue_mask = 0;
switch (type)
{
case FREE_IMAGE_TYPE.FIT_BITMAP:
switch (bpp)
{
case 1:
case 4:
case 8:
result = true;
break;
case 16:
result = true;
red_mask = FI16_555_RED_MASK;
green_mask = FI16_555_GREEN_MASK;
blue_mask = FI16_555_BLUE_MASK;
break;
case 24:
case 32:
result = true;
red_mask = FI_RGBA_RED_MASK;
green_mask = FI_RGBA_GREEN_MASK;
blue_mask = FI_RGBA_BLUE_MASK;
break;
}
break;
case FREE_IMAGE_TYPE.FIT_UNKNOWN:
break;
default:
result = true;
break;
}
return result;
}
/// <summary>
/// Compares two FreeImage bitmaps.
/// </summary>
/// <param name="dib1">The first bitmap to compare.</param>
/// <param name="dib2">The second bitmap to compare.</param>
/// <param name="flags">Determines which components of the bitmaps will be compared.</param>
/// <returns>True in case both bitmaps match the compare conditions, false otherwise.</returns>
public static bool Compare(FIBITMAP dib1, FIBITMAP dib2, FREE_IMAGE_COMPARE_FLAGS flags)
{
// Check whether one bitmap is null
if (dib1.IsNull ^ dib2.IsNull)
{
return false;
}
// Check whether both pointers are the same
if (dib1 == dib2)
{
return true;
}
if (((flags & FREE_IMAGE_COMPARE_FLAGS.HEADER) > 0) && (!CompareHeader(dib1, dib2)))
{
return false;
}
if (((flags & FREE_IMAGE_COMPARE_FLAGS.PALETTE) > 0) && (!ComparePalette(dib1, dib2)))
{
return false;
}
if (((flags & FREE_IMAGE_COMPARE_FLAGS.DATA) > 0) && (!CompareData(dib1, dib2)))
{
return false;
}
if (((flags & FREE_IMAGE_COMPARE_FLAGS.METADATA) > 0) && (!CompareMetadata(dib1, dib2)))
{
return false;
}
return true;
}
private static unsafe bool CompareHeader(FIBITMAP dib1, FIBITMAP dib2)
{
IntPtr i1 = GetInfoHeader(dib1);
IntPtr i2 = GetInfoHeader(dib2);
return CompareMemory((void*)i1, (void*)i2, sizeof(BITMAPINFOHEADER));
}
private static unsafe bool ComparePalette(FIBITMAP dib1, FIBITMAP dib2)
{
IntPtr pal1 = GetPalette(dib1), pal2 = GetPalette(dib2);
bool hasPalette1 = pal1 != IntPtr.Zero;
bool hasPalette2 = pal2 != IntPtr.Zero;
if (hasPalette1 ^ hasPalette2)
{
return false;
}
if (!hasPalette1)
{
return true;
}
uint colors = GetColorsUsed(dib1);
if (colors != GetColorsUsed(dib2))
{
return false;
}
return CompareMemory((void*)pal1, (void*)pal2, sizeof(RGBQUAD) * colors);
}
private static unsafe bool CompareData(FIBITMAP dib1, FIBITMAP dib2)
{
uint width = GetWidth(dib1);
if (width != GetWidth(dib2))
{
return false;
}
uint height = GetHeight(dib1);
if (height != GetHeight(dib2))
{
return false;
}
uint bpp = GetBPP(dib1);
if (bpp != GetBPP(dib2))
{
return false;
}
if (GetColorType(dib1) != GetColorType(dib2))
{
return false;
}
FREE_IMAGE_TYPE type = GetImageType(dib1);
if (type != GetImageType(dib2))
{
return false;
}
if (GetRedMask(dib1) != GetRedMask(dib2))
{
return false;
}
if (GetGreenMask(dib1) != GetGreenMask(dib2))
{
return false;
}
if (GetBlueMask(dib1) != GetBlueMask(dib2))
{
return false;
}
byte* ptr1, ptr2;
int fullBytes;
int shift;
uint line = GetLine(dib1);
if (type == FREE_IMAGE_TYPE.FIT_BITMAP)
{
switch (bpp)
{
case 32:
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (!CompareMemory(ptr1, ptr2, line))
{
return false;
}
}
break;
case 24:
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (!CompareMemory(ptr1, ptr2, line))
{
return false;
}
}
break;
case 16:
short* sPtr1, sPtr2;
short mask = (short)(GetRedMask(dib1) | GetGreenMask(dib1) | GetBlueMask(dib1));
if (mask == -1)
{
for (int i = 0; i < height; i++)
{
sPtr1 = (short*)GetScanLine(dib1, i);
sPtr2 = (short*)GetScanLine(dib2, i);
if (!CompareMemory(sPtr1, sPtr1, line))
{
return false;
}
}
}
else
{
for (int i = 0; i < height; i++)
{
sPtr1 = (short*)GetScanLine(dib1, i);
sPtr2 = (short*)GetScanLine(dib2, i);
for (int x = 0; x < width; x++)
{
if ((sPtr1[x] & mask) != (sPtr2[x] & mask))
{
return false;
}
}
}
}
break;
case 8:
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (!CompareMemory(ptr1, ptr2, line))
{
return false;
}
}
break;
case 4:
fullBytes = (int)width / 2;
shift = (width % 2) == 0 ? 8 : 4;
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (fullBytes != 0)
{
if (!CompareMemory(ptr1, ptr2, fullBytes))
{
return false;
}
ptr1 += fullBytes;
ptr2 += fullBytes;
}
if (shift != 8)
{
if ((ptr1[0] >> shift) != (ptr2[0] >> shift))
{
return false;
}
}
}
break;
case 1:
fullBytes = (int)width / 8;
shift = 8 - ((int)width % 8);
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (fullBytes != 0)
{
if (!CompareMemory(ptr1, ptr2, fullBytes))
{
return false;
}
ptr1 += fullBytes;
ptr2 += fullBytes;
}
if (shift != 8)
{
if ((ptr1[0] >> shift) != (ptr2[0] >> shift))
{
return false;
}
}
}
break;
default:
throw new NotSupportedException("Only 1, 4, 8, 16, 24 and 32 bpp bitmaps are supported.");
}
}
else
{
for (int i = 0; i < height; i++)
{
ptr1 = (byte*)GetScanLine(dib1, i);
ptr2 = (byte*)GetScanLine(dib2, i);
if (!CompareMemory(ptr1, ptr2, line))
{
return false;
}
}
}
return true;
}
private static bool CompareMetadata(FIBITMAP dib1, FIBITMAP dib2)
{
MetadataTag tag1, tag2;
foreach (FREE_IMAGE_MDMODEL metadataModel in FREE_IMAGE_MDMODELS)
{
if (GetMetadataCount(metadataModel, dib1) !=
GetMetadataCount(metadataModel, dib2))
{
return false;
}
if (GetMetadataCount(metadataModel, dib1) == 0)
{
continue;
}
FIMETADATA mdHandle = FindFirstMetadata(metadataModel, dib1, out tag1);
if (mdHandle.IsNull)
{
continue;
}
do
{
if ((!GetMetadata(metadataModel, dib2, tag1.Key, out tag2)) || (tag1 != tag2))
{
FindCloseMetadata(mdHandle);
return false;
}
}
while (FindNextMetadata(mdHandle, out tag1));
FindCloseMetadata(mdHandle);
}
return true;
}
/// <summary>
/// Returns the FreeImage bitmap's transparency table.
/// The array is empty in case the bitmap has no transparency table.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>The FreeImage bitmap's transparency table.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe byte[] GetTransparencyTableEx(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
uint count = GetTransparencyCount(dib);
byte[] result = new byte[count];
byte* ptr = (byte*)GetTransparencyTable(dib);
fixed (byte* dst = result)
{
CopyMemory(dst, ptr, count);
}
return result;
}
/// <summary>
/// Set the FreeImage bitmap's transparency table. Only affects palletised bitmaps.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="table">The FreeImage bitmap's new transparency table.</param>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> or <paramref name="table"/> is null.</exception>
public static void SetTransparencyTable(FIBITMAP dib, byte[] table)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
if (table == null)
{
throw new ArgumentNullException("table");
}
SetTransparencyTable(dib, table, table.Length);
}
/// <summary>
/// This function returns the number of unique colors actually used by the
/// specified 1-, 4-, 8-, 16-, 24- or 32-bit image. This might be different from
/// what function FreeImage_GetColorsUsed() returns, which actually returns the
/// palette size for palletised images. Works for
/// <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/> type images only.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>Returns the number of unique colors used by the image specified or
/// zero, if the image type cannot be handled.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe int GetUniqueColors(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
int result = 0;
if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
{
BitArray bitArray;
int uniquePalEnts;
int hashcode;
byte[] lut;
int width = (int)GetWidth(dib);
int height = (int)GetHeight(dib);
switch (GetBPP(dib))
{
case 1:
result = 1;
lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
if (uniquePalEnts == 1)
{
break;
}
if ((*(byte*)GetScanLine(dib, 0) & 0x80) == 0)
{
for (int y = 0; y < height; y++)
{
byte* scanline = (byte*)GetScanLine(dib, y);
int mask = 0x80;
for (int x = 0; x < width; x++)
{
if ((scanline[x / 8] & mask) > 0)
{
return 2;
}
mask = (mask == 0x1) ? 0x80 : (mask >> 1);
}
}
}
else
{
for (int y = 0; y < height; y++)
{
byte* scanline = (byte*)GetScanLine(dib, y);
int mask = 0x80;
for (int x = 0; x < width; x++)
{
if ((scanline[x / 8] & mask) == 0)
{
return 2;
}
mask = (mask == 0x1) ? 0x80 : (mask >> 1);
}
}
}
break;
case 4:
bitArray = new BitArray(0x10);
lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
if (uniquePalEnts == 1)
{
result = 1;
break;
}
for (int y = 0; (y < height) && (result < uniquePalEnts); y++)
{
byte* scanline = (byte*)GetScanLine(dib, y);
bool top = true;
for (int x = 0; (x < width) && (result < uniquePalEnts); x++)
{
if (top)
{
hashcode = lut[scanline[x / 2] >> 4];
}
else
{
hashcode = lut[scanline[x / 2] & 0xF];
}
top = !top;
if (!bitArray[hashcode])
{
bitArray[hashcode] = true;
result++;
}
}
}
break;
case 8:
bitArray = new BitArray(0x100);
lut = CreateShrunkenPaletteLUT(dib, out uniquePalEnts);
if (uniquePalEnts == 1)
{
result = 1;
break;
}
for (int y = 0; (y < height) && (result < uniquePalEnts); y++)
{
byte* scanline = (byte*)GetScanLine(dib, y);
for (int x = 0; (x < width) && (result < uniquePalEnts); x++)
{
hashcode = lut[scanline[x]];
if (!bitArray[hashcode])
{
bitArray[hashcode] = true;
result++;
}
}
}
break;
case 16:
bitArray = new BitArray(0x10000);
for (int y = 0; y < height; y++)
{
short* scanline = (short*)GetScanLine(dib, y);
for (int x = 0; x < width; x++, scanline++)
{
hashcode = *scanline;
if (!bitArray[hashcode])
{
bitArray[hashcode] = true;
result++;
}
}
}
break;
case 24:
bitArray = new BitArray(0x1000000);
for (int y = 0; y < height; y++)
{
byte* scanline = (byte*)GetScanLine(dib, y);
for (int x = 0; x < width; x++, scanline += 3)
{
hashcode = *((int*)scanline) & 0x00FFFFFF;
if (!bitArray[hashcode])
{
bitArray[hashcode] = true;
result++;
}
}
}
break;
case 32:
bitArray = new BitArray(0x1000000);
for (int y = 0; y < height; y++)
{
int* scanline = (int*)GetScanLine(dib, y);
for (int x = 0; x < width; x++, scanline++)
{
hashcode = *scanline & 0x00FFFFFF;
if (!bitArray[hashcode])
{
bitArray[hashcode] = true;
result++;
}
}
}
break;
}
}
return result;
}
/// <summary>
/// Verifies whether the FreeImage bitmap is 16bit 555.
/// </summary>
/// <param name="dib">The FreeImage bitmap to verify.</param>
/// <returns><b>true</b> if the bitmap is RGB16-555; otherwise <b>false</b>.</returns>
public static bool IsRGB555(FIBITMAP dib)
{
return ((GetRedMask(dib) == FI16_555_RED_MASK) &&
(GetGreenMask(dib) == FI16_555_GREEN_MASK) &&
(GetBlueMask(dib) == FI16_555_BLUE_MASK));
}
/// <summary>
/// Verifies whether the FreeImage bitmap is 16bit 565.
/// </summary>
/// <param name="dib">The FreeImage bitmap to verify.</param>
/// <returns><b>true</b> if the bitmap is RGB16-565; otherwise <b>false</b>.</returns>
public static bool IsRGB565(FIBITMAP dib)
{
return ((GetRedMask(dib) == FI16_565_RED_MASK) &&
(GetGreenMask(dib) == FI16_565_GREEN_MASK) &&
(GetBlueMask(dib) == FI16_565_BLUE_MASK));
}
#endregion
#region ICC profile functions
/// <summary>
/// Creates a new ICC-Profile for a FreeImage bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="data">The data of the new ICC-Profile.</param>
/// <returns>The new ICC-Profile of the bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data)
{
return new FIICCPROFILE(dib, data);
}
/// <summary>
/// Creates a new ICC-Profile for a FreeImage bitmap.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="data">The data of the new ICC-Profile.</param>
/// <param name="size">The number of bytes of <paramref name="data"/> to use.</param>
/// <returns>The new ICC-Profile of the FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data, int size)
{
return new FIICCPROFILE(dib, data, size);
}
#endregion
#region Conversion functions
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion)
{
return ConvertColorDepth(
dib,
conversion,
128,
FREE_IMAGE_DITHER.FID_FS,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
false);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
bool unloadSource)
{
return ConvertColorDepth(
dib,
conversion,
128,
FREE_IMAGE_DITHER.FID_FS,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
unloadSource);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="threshold">Threshold value when converting with
/// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
byte threshold)
{
return ConvertColorDepth(
dib,
conversion,
threshold,
FREE_IMAGE_DITHER.FID_FS,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
false);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="ditherMethod">Dither algorithm when converting
/// with <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
FREE_IMAGE_DITHER ditherMethod)
{
return ConvertColorDepth(
dib,
conversion,
128,
ditherMethod,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
false);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
FREE_IMAGE_QUANTIZE quantizationMethod)
{
return ConvertColorDepth(
dib,
conversion,
128,
FREE_IMAGE_DITHER.FID_FS,
quantizationMethod,
false);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="threshold">Threshold value when converting with
/// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
byte threshold,
bool unloadSource)
{
return ConvertColorDepth(
dib,
conversion,
threshold,
FREE_IMAGE_DITHER.FID_FS,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
unloadSource);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="ditherMethod">Dither algorithm when converting with
/// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
FREE_IMAGE_DITHER ditherMethod,
bool unloadSource)
{
return ConvertColorDepth(
dib,
conversion,
128,
ditherMethod,
FREE_IMAGE_QUANTIZE.FIQ_WUQUANT,
unloadSource);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
FREE_IMAGE_QUANTIZE quantizationMethod,
bool unloadSource)
{
return ConvertColorDepth(
dib,
conversion,
128,
FREE_IMAGE_DITHER.FID_FS,
quantizationMethod,
unloadSource);
}
/// <summary>
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="conversion">The desired output format.</param>
/// <param name="threshold">Threshold value when converting with
/// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD"/>.</param>
/// <param name="ditherMethod">Dither algorithm when converting with
/// <see cref="FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER"/>.</param>
/// <param name="quantizationMethod">The quantization algorithm for conversion to 8-bit color depth.</param>
/// <param name="unloadSource">When true the structure will be unloaded on success.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
internal static FIBITMAP ConvertColorDepth(
FIBITMAP dib,
FREE_IMAGE_COLOR_DEPTH conversion,
byte threshold,
FREE_IMAGE_DITHER ditherMethod,
FREE_IMAGE_QUANTIZE quantizationMethod,
bool unloadSource)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
FIBITMAP result = new FIBITMAP();
FIBITMAP dibTemp = new FIBITMAP();
uint bpp = GetBPP(dib);
bool reorderPalette = ((conversion & FREE_IMAGE_COLOR_DEPTH.FICD_REORDER_PALETTE) > 0);
bool forceGreyscale = ((conversion & FREE_IMAGE_COLOR_DEPTH.FICD_FORCE_GREYSCALE) > 0);
if (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP)
{
switch (conversion & (FREE_IMAGE_COLOR_DEPTH)0xFF)
{
case FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_THRESHOLD:
if (bpp != 1)
{
if (forceGreyscale)
{
result = Threshold(dib, threshold);
}
else
{
dibTemp = ConvertTo24Bits(dib);
result = ColorQuantizeEx(dibTemp, quantizationMethod, 2, null, 1);
Unload(dibTemp);
}
}
else
{
bool isGreyscale = IsGreyscaleImage(dib);
if ((forceGreyscale && (!isGreyscale)) ||
(reorderPalette && isGreyscale))
{
result = Threshold(dib, threshold);
}
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_01_BPP_DITHER:
if (bpp != 1)
{
if (forceGreyscale)
{
result = Dither(dib, ditherMethod);
}
else
{
dibTemp = ConvertTo24Bits(dib);
result = ColorQuantizeEx(dibTemp, quantizationMethod, 2, null, 1);
Unload(dibTemp);
}
}
else
{
bool isGreyscale = IsGreyscaleImage(dib);
if ((forceGreyscale && (!isGreyscale)) ||
(reorderPalette && isGreyscale))
{
result = Dither(dib, ditherMethod);
}
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_04_BPP:
if (bpp != 4)
{
// Special case when 1bpp and FIC_PALETTE
if (forceGreyscale ||
((bpp == 1) && (GetColorType(dib) == FREE_IMAGE_COLOR_TYPE.FIC_PALETTE)))
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo4Bits(dibTemp);
Unload(dibTemp);
}
else
{
dibTemp = ConvertTo24Bits(dib);
result = ColorQuantizeEx(dibTemp, quantizationMethod, 16, null, 4);
Unload(dibTemp);
}
}
else
{
bool isGreyscale = IsGreyscaleImage(dib);
if ((forceGreyscale && (!isGreyscale)) ||
(reorderPalette && isGreyscale))
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo4Bits(dibTemp);
Unload(dibTemp);
}
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP:
if (bpp != 8)
{
if (forceGreyscale)
{
result = ConvertToGreyscale(dib);
}
else
{
dibTemp = ConvertTo24Bits(dib);
result = ColorQuantize(dibTemp, quantizationMethod);
Unload(dibTemp);
}
}
else
{
bool isGreyscale = IsGreyscaleImage(dib);
if ((forceGreyscale && (!isGreyscale)) || (reorderPalette && isGreyscale))
{
result = ConvertToGreyscale(dib);
}
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_16_BPP_555:
if (forceGreyscale)
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo16Bits555(dibTemp);
Unload(dibTemp);
}
else if (bpp != 16 || GetRedMask(dib) != FI16_555_RED_MASK || GetGreenMask(dib) != FI16_555_GREEN_MASK || GetBlueMask(dib) != FI16_555_BLUE_MASK)
{
result = ConvertTo16Bits555(dib);
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_16_BPP:
if (forceGreyscale)
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo16Bits565(dibTemp);
Unload(dibTemp);
}
else if (bpp != 16 || GetRedMask(dib) != FI16_565_RED_MASK || GetGreenMask(dib) != FI16_565_GREEN_MASK || GetBlueMask(dib) != FI16_565_BLUE_MASK)
{
result = ConvertTo16Bits565(dib);
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_24_BPP:
if (forceGreyscale)
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo24Bits(dibTemp);
Unload(dibTemp);
}
else if (bpp != 24)
{
result = ConvertTo24Bits(dib);
}
break;
case FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP:
if (forceGreyscale)
{
dibTemp = ConvertToGreyscale(dib);
result = ConvertTo32Bits(dibTemp);
Unload(dibTemp);
}
else if (bpp != 32)
{
result = ConvertTo32Bits(dib);
}
break;
}
}
if (result.IsNull)
{
return dib;
}
if (unloadSource)
{
Unload(dib);
}
return result;
}
/// <summary>
/// ColorQuantizeEx is an extension to the <see cref="ColorQuantize(FIBITMAP, FREE_IMAGE_QUANTIZE)"/>
/// method that provides additional options used to quantize a 24-bit image to any
/// number of colors (up to 256), as well as quantize a 24-bit image using a
/// provided palette.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="quantize">Specifies the color reduction algorithm to be used.</param>
/// <param name="PaletteSize">Size of the desired output palette.</param>
/// <param name="ReservePalette">The provided palette.</param>
/// <param name="minColorDepth"><b>true</b> to create a bitmap with the smallest possible
/// color depth for the specified <paramref name="PaletteSize"/>.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP ColorQuantizeEx(FIBITMAP dib, FREE_IMAGE_QUANTIZE quantize, int PaletteSize, RGBQUAD[] ReservePalette, bool minColorDepth)
{
FIBITMAP result;
if (minColorDepth)
{
int bpp;
if (PaletteSize >= 256)
bpp = 8;
else if (PaletteSize > 2)
bpp = 4;
else
bpp = 1;
result = ColorQuantizeEx(dib, quantize, PaletteSize, ReservePalette, bpp);
}
else
{
result = ColorQuantizeEx(dib, quantize, PaletteSize, ReservePalette, 8);
}
return result;
}
/// <summary>
/// ColorQuantizeEx is an extension to the <see cref="ColorQuantize(FIBITMAP, FREE_IMAGE_QUANTIZE)"/>
/// method that provides additional options used to quantize a 24-bit image to any
/// number of colors (up to 256), as well as quantize a 24-bit image using a
/// partial or full provided palette.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="quantize">Specifies the color reduction algorithm to be used.</param>
/// <param name="PaletteSize">Size of the desired output palette.</param>
/// <param name="ReservePalette">The provided palette.</param>
/// <param name="bpp">The desired color depth of the created image.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP ColorQuantizeEx(FIBITMAP dib, FREE_IMAGE_QUANTIZE quantize, int PaletteSize, RGBQUAD[] ReservePalette, int bpp)
{
unsafe
{
FIBITMAP result = FIBITMAP.Zero;
FIBITMAP temp = FIBITMAP.Zero;
int reservedSize = (ReservePalette == null) ? 0 : ReservePalette.Length;
if (bpp == 8)
{
result = ColorQuantizeEx(dib, quantize, PaletteSize, reservedSize, ReservePalette);
}
else if (bpp == 4)
{
temp = ColorQuantizeEx(dib, quantize, Math.Min(16, PaletteSize), reservedSize, ReservePalette);
if (!temp.IsNull)
{
result = Allocate((int)GetWidth(temp), (int)GetHeight(temp), 4, 0, 0, 0);
CloneMetadata(result, temp);
CopyMemory(GetPalette(result), GetPalette(temp), sizeof(RGBQUAD) * 16);
for (int y = (int)GetHeight(temp) - 1; y >= 0; y--)
{
Scanline<byte> srcScanline = new Scanline<byte>(temp, y);
Scanline<FI4BIT> dstScanline = new Scanline<FI4BIT>(result, y);
for (int x = (int)GetWidth(temp) - 1; x >= 0; x--)
{
dstScanline[x] = srcScanline[x];
}
}
}
}
else if (bpp == 1)
{
temp = ColorQuantizeEx(dib, quantize, 2, reservedSize, ReservePalette);
if (!temp.IsNull)
{
result = Allocate((int)GetWidth(temp), (int)GetHeight(temp), 1, 0, 0, 0);
CloneMetadata(result, temp);
CopyMemory(GetPalette(result), GetPalette(temp), sizeof(RGBQUAD) * 2);
for (int y = (int)GetHeight(temp) - 1; y >= 0; y--)
{
Scanline<byte> srcScanline = new Scanline<byte>(temp, y);
Scanline<FI1BIT> dstScanline = new Scanline<FI1BIT>(result, y);
for (int x = (int)GetWidth(temp) - 1; x >= 0; x--)
{
dstScanline[x] = srcScanline[x];
}
}
}
}
UnloadEx(ref temp);
return result;
}
}
#endregion
#region Metadata
/// <summary>
/// Copies metadata from one FreeImage bitmap to another.
/// </summary>
/// <param name="src">Source FreeImage bitmap containing the metadata.</param>
/// <param name="dst">FreeImage bitmap to copy the metadata to.</param>
/// <param name="flags">Flags to switch different copy modes.</param>
/// <returns>Returns -1 on failure else the number of copied tags.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="src"/> or <paramref name="dst"/> is null.</exception>
public static int CloneMetadataEx(FIBITMAP src, FIBITMAP dst, FREE_IMAGE_METADATA_COPY flags)
{
if (src.IsNull)
{
throw new ArgumentNullException("src");
}
if (dst.IsNull)
{
throw new ArgumentNullException("dst");
}
FITAG tag = new FITAG(), tag2 = new FITAG();
int copied = 0;
// Clear all existing metadata
if ((flags & FREE_IMAGE_METADATA_COPY.CLEAR_EXISTING) > 0)
{
foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
{
if (!SetMetadata(model, dst, null, tag))
{
return -1;
}
}
}
bool keep = !((flags & FREE_IMAGE_METADATA_COPY.REPLACE_EXISTING) > 0);
foreach (FREE_IMAGE_MDMODEL model in FREE_IMAGE_MDMODELS)
{
FIMETADATA mData = FindFirstMetadata(model, src, out tag);
if (mData.IsNull) continue;
do
{
string key = GetTagKey(tag);
if (!(keep && GetMetadata(model, dst, key, out tag2)))
{
if (SetMetadata(model, dst, key, tag))
{
copied++;
}
}
}
while (FindNextMetadata(mData, out tag));
FindCloseMetadata(mData);
}
return copied;
}
/// <summary>
/// Returns the comment of a JPEG, PNG or GIF image.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <returns>Comment of the FreeImage bitmp, or null in case no comment exists.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static string GetImageComment(FIBITMAP dib)
{
string result = null;
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
FITAG tag;
if (GetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", out tag))
{
MetadataTag metadataTag = new MetadataTag(tag, FREE_IMAGE_MDMODEL.FIMD_COMMENTS);
result = metadataTag.Value as string;
}
return result;
}
/// <summary>
/// Sets the comment of a JPEG, PNG or GIF image.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="comment">New comment of the FreeImage bitmap.
/// Use null to remove the comment.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static bool SetImageComment(FIBITMAP dib, string comment)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
bool result;
if (comment != null)
{
FITAG tag = CreateTag();
MetadataTag metadataTag = new MetadataTag(tag, FREE_IMAGE_MDMODEL.FIMD_COMMENTS);
metadataTag.Value = comment;
result = SetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", tag);
DeleteTag(tag);
}
else
{
result = SetMetadata(FREE_IMAGE_MDMODEL.FIMD_COMMENTS, dib, "Comment", FITAG.Zero);
}
return result;
}
/// <summary>
/// Retrieve a metadata attached to a FreeImage bitmap.
/// </summary>
/// <param name="model">The metadata model to look for.</param>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="key">The metadata field name.</param>
/// <param name="tag">A <see cref="MetadataTag"/> structure returned by the function.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static bool GetMetadata(
FREE_IMAGE_MDMODEL model,
FIBITMAP dib,
string key,
out MetadataTag tag)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
FITAG _tag;
bool result;
if (GetMetadata(model, dib, key, out _tag))
{
tag = new MetadataTag(_tag, model);
result = true;
}
else
{
tag = null;
result = false;
}
return result;
}
/// <summary>
/// Attach a new metadata tag to a FreeImage bitmap.
/// </summary>
/// <param name="model">The metadata model used to store the tag.</param>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="key">The tag field name.</param>
/// <param name="tag">The <see cref="MetadataTag"/> to be attached.</param>
/// <returns>Returns true on success, false on failure.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static bool SetMetadata(
FREE_IMAGE_MDMODEL model,
FIBITMAP dib,
string key,
MetadataTag tag)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return SetMetadata(model, dib, key, tag.tag);
}
/// <summary>
/// Provides information about the first instance of a tag that matches the metadata model.
/// </summary>
/// <param name="model">The model to match.</param>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="tag">Tag that matches the metadata model.</param>
/// <returns>Unique search handle that can be used to call FindNextMetadata or FindCloseMetadata.
/// Null if the metadata model does not exist.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static FIMETADATA FindFirstMetadata(
FREE_IMAGE_MDMODEL model,
FIBITMAP dib,
out MetadataTag tag)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
FITAG _tag;
FIMETADATA result = FindFirstMetadata(model, dib, out _tag);
if (result.IsNull)
{
tag = null;
return result;
}
tag = new MetadataTag(_tag, model);
if (metaDataSearchHandler.ContainsKey(result))
{
metaDataSearchHandler[result] = model;
}
else
{
metaDataSearchHandler.Add(result, model);
}
return result;
}
/// <summary>
/// Find the next tag, if any, that matches the metadata model argument in a previous call
/// to FindFirstMetadata, and then alters the tag object contents accordingly.
/// </summary>
/// <param name="mdhandle">Unique search handle provided by FindFirstMetadata.</param>
/// <param name="tag">Tag that matches the metadata model.</param>
/// <returns>Returns true on success, false on failure.</returns>
public static bool FindNextMetadata(FIMETADATA mdhandle, out MetadataTag tag)
{
FITAG _tag;
bool result;
if (FindNextMetadata(mdhandle, out _tag))
{
tag = new MetadataTag(_tag, metaDataSearchHandler[mdhandle]);
result = true;
}
else
{
tag = null;
result = false;
}
return result;
}
/// <summary>
/// Closes the specified metadata search handle and releases associated resources.
/// </summary>
/// <param name="mdhandle">The handle to close.</param>
public static void FindCloseMetadata(FIMETADATA mdhandle)
{
if (metaDataSearchHandler.ContainsKey(mdhandle))
{
metaDataSearchHandler.Remove(mdhandle);
}
FindCloseMetadata_(mdhandle);
}
/// <summary>
/// This dictionary links FIMETADATA handles and FREE_IMAGE_MDMODEL models.
/// </summary>
private static Dictionary<FIMETADATA, FREE_IMAGE_MDMODEL> metaDataSearchHandler
= new Dictionary<FIMETADATA, FREE_IMAGE_MDMODEL>(1);
#endregion
#region Rotation and Flipping
/// <summary>
/// This function rotates a 1-, 8-bit greyscale or a 24-, 32-bit color image by means of 3 shears.
/// 1-bit images rotation is limited to integer multiple of 90<39>.
/// <c>null</c> is returned for other values.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="angle">The angle of rotation.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP Rotate(FIBITMAP dib, double angle)
{
return Rotate(dib, angle, IntPtr.Zero);
}
/// <summary>
/// This function rotates a 1-, 8-bit greyscale or a 24-, 32-bit color image by means of 3 shears.
/// 1-bit images rotation is limited to integer multiple of 90<39>.
/// <c>null</c> is returned for other values.
/// </summary>
/// <typeparam name="T">The type of the color to use as background.</typeparam>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="angle">The angle of rotation.</param>
/// <param name="backgroundColor">The color used used to fill the bitmap's background.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
public static FIBITMAP Rotate<T>(FIBITMAP dib, double angle, T? backgroundColor) where T : struct
{
if (backgroundColor.HasValue)
{
GCHandle handle = new GCHandle();
try
{
T[] buffer = new T[] { backgroundColor.Value };
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return Rotate(dib, angle, handle.AddrOfPinnedObject());
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
else
{
return Rotate(dib, angle, IntPtr.Zero);
}
}
/// <summary>
/// Rotates a 4-bit color FreeImage bitmap.
/// Allowed values for <paramref name="angle"/> are 90, 180 and 270.
/// In case <paramref name="angle"/> is 0 or 360 a clone is returned.
/// 0 is returned for other values or in case the rotation fails.
/// </summary>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="angle">The angle of rotation.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function is kind of temporary due to FreeImage's lack of
/// rotating 4-bit images. It's particularly used by <see cref="FreeImageBitmap"/>'s
/// method RotateFlip. This function will be removed as soon as FreeImage
/// supports rotating 4-bit images.
/// </remarks>
/// <exception cref="ArgumentNullException">
/// <paramref name="dib"/> is null.</exception>
public static unsafe FIBITMAP Rotate4bit(FIBITMAP dib, double angle)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
FIBITMAP result = new FIBITMAP();
int ang = (int)angle;
if ((GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP) &&
(GetBPP(dib) == 4) &&
((ang % 90) == 0))
{
int width, height, xOrg, yOrg;
Scanline<FI4BIT>[] src, dst;
width = (int)GetWidth(dib);
height = (int)GetHeight(dib);
byte index = 0;
switch (ang)
{
case 90:
result = Allocate(height, width, 4, 0, 0, 0);
if (result.IsNull)
{
break;
}
CopyPalette(dib, result);
src = Get04BitScanlines(dib);
dst = Get04BitScanlines(result);
for (int y = 0; y < width; y++)
{
yOrg = height - 1;
for (int x = 0; x < height; x++, yOrg--)
{
index = src[yOrg][y];
dst[y][x] = index;
}
}
break;
case 180:
result = Allocate(width, height, 4, 0, 0, 0);
if (result.IsNull)
{
break;
}
CopyPalette(dib, result);
src = Get04BitScanlines(dib);
dst = Get04BitScanlines(result);
yOrg = height - 1;
for (int y = 0; y < height; y++, yOrg--)
{
xOrg = width - 1;
for (int x = 0; x < width; x++, xOrg--)
{
index = src[yOrg][xOrg];
dst[y][x] = index;
}
}
break;
case 270:
result = Allocate(height, width, 4, 0, 0, 0);
if (result.IsNull)
{
break;
}
CopyPalette(dib, result);
src = Get04BitScanlines(dib);
dst = Get04BitScanlines(result);
xOrg = width - 1;
for (int y = 0; y < width; y++, xOrg--)
{
for (int x = 0; x < height; x++)
{
index = src[x][xOrg];
dst[y][x] = index;
}
}
break;
case 0:
case 360:
result = Clone(dib);
break;
}
}
return result;
}
#endregion
#region Upsampling / downsampling
/// <summary>
/// Enlarges or shrinks the FreeImage bitmap selectively per side and fills newly added areas
/// with the specified background color. See remarks for further details.
/// </summary>
/// <typeparam name="T">The type of the specified color.</typeparam>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="left">The number of pixels, the image should be enlarged on its left side.
/// Negative values shrink the image on its left side.</param>
/// <param name="top">The number of pixels, the image should be enlarged on its top side.
/// Negative values shrink the image on its top side.</param>
/// <param name="right">The number of pixels, the image should be enlarged on its right side.
/// Negative values shrink the image on its right side.</param>
/// <param name="bottom">The number of pixels, the image should be enlarged on its bottom side.
/// Negative values shrink the image on its bottom side.</param>
/// <param name="color">The color, the enlarged sides of the image should be filled with.</param>
/// <param name="options">Options that affect the color search process for palletized images.</param>
/// <returns>Handle to a FreeImage bitmap.</returns>
/// <remarks>
/// This function enlarges or shrinks an image selectively per side.
/// The main purpose of this function is to add borders to an image.
/// To add a border to any of the image's sides, a positive integer value must be passed in
/// any of the parameters <paramref name="left"/>, <paramref name="top"/>, <paramref name="right"/>
/// or <paramref name="bottom"/>. This value represents the border's
/// width in pixels. Newly created parts of the image (the border areas) are filled with the
/// specified <paramref name="color"/>.
/// Specifying a negative integer value for a certain side, will shrink or crop the image on
/// this side. Consequently, specifying zero for a certain side will not change the image's
/// extension on that side.
/// <para/>
/// So, calling this function with all parameters <paramref name="left"/>, <paramref name="top"/>,
/// <paramref name="right"/> and <paramref name="bottom"/> set to zero, is
/// effectively the same as calling function <see cref="Clone"/>; setting all parameters
/// <paramref name="left"/>, <paramref name="top"/>, <paramref name="right"/> and
/// <paramref name="bottom"/> to value equal to or smaller than zero, my easily be substituted
/// by a call to function <see cref="Copy"/>. Both these cases produce a new image, which is
/// guaranteed not to be larger than the input image. Thus, since the specified
/// <paramref name="color"/> is not needed in these cases, <paramref name="color"/>
/// may be <c>null</c>.
/// <para/>
/// Both parameters <paramref name="color"/> and <paramref name="options"/> work according to
/// function <see cref="FillBackground&lt;T&gt;"/>. So, please refer to the documentation of
/// <see cref="FillBackground&lt;T&gt;"/> to learn more about parameters <paramref name="color"/>
/// and <paramref name="options"/>. For palletized images, the palette of the input image is
/// transparently copied to the newly created enlarged or shrunken image, so any color look-ups
/// are performed on this palette.
/// </remarks>
/// <example>
/// // create a white color<br/>
/// RGBQUAD c;<br/>
/// c.rgbRed = 0xFF;<br/>
/// c.rgbGreen = 0xFF;<br/>
/// c.rgbBlue = 0xFF;<br/>
/// c.rgbReserved = 0x00;<br/>
/// <br/>
/// // add a white, symmetric 10 pixel wide border to the image<br/>
/// dib2 = FreeImage_EnlargeCanvas(dib, 10, 10, 10, 10, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
/// <br/>
/// // add white, 20 pixel wide stripes to the top and bottom side of the image<br/>
/// dib3 = FreeImage_EnlargeCanvas(dib, 0, 20, 0, 20, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
/// <br/>
/// // add white, 30 pixel wide stripes to the right side of the image and<br/>
/// // cut off the 40 leftmost pixel columns<br/>
/// dib3 = FreeImage_EnlargeCanvas(dib, -40, 0, 30, 0, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);<br/>
/// </example>
public static FIBITMAP EnlargeCanvas<T>(FIBITMAP dib, int left, int top, int right, int bottom,
T? color, FREE_IMAGE_COLOR_OPTIONS options) where T : struct
{
if (dib.IsNull)
return FIBITMAP.Zero;
if (color.HasValue)
{
if (!CheckColorType(GetImageType(dib), color.Value))
return FIBITMAP.Zero;
GCHandle handle = new GCHandle();
try
{
T[] buffer = new T[] { color.Value };
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return EnlargeCanvas(dib, left, top, right, bottom, handle.AddrOfPinnedObject(), options);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
else
{
return EnlargeCanvas(dib, left, top, right, bottom, IntPtr.Zero, options);
}
}
#endregion
#region Color
/// <summary>
/// Sets all pixels of the specified image to the color provided through the
/// <paramref name="color"/> parameter. See remarks for further details.
/// </summary>
/// <typeparam name="T">The type of the specified color.</typeparam>
/// <param name="dib">Handle to a FreeImage bitmap.</param>
/// <param name="color">The color to fill the bitmap with. See remarks for further details.</param>
/// <param name="options">Options that affect the color search process for palletized images.</param>
/// <returns><c>true</c> on success, <c>false</c> on failure.</returns>
/// <remarks>
/// This function sets all pixels of an image to the color provided through
/// the <paramref name="color"/> parameter. <see cref="RGBQUAD"/> is used for standard type images.
/// For non standard type images the underlaying structure is used.
/// <para/>
/// So, <paramref name="color"/> must be of type <see cref="Double"/>, if the image to be filled is of type
/// <see cref="FREE_IMAGE_TYPE.FIT_DOUBLE"/> and must be a <see cref="FIRGBF"/> structure if the
/// image is of type <see cref="FREE_IMAGE_TYPE.FIT_RGBF"/> and so on.
/// <para/>
/// However, the fill color is always specified through a <see cref="RGBQUAD"/> structure
/// for all images of type <see cref="FREE_IMAGE_TYPE.FIT_BITMAP"/>.
/// So, for 32- and 24-bit images, the red, green and blue members of the <see cref="RGBQUAD"/>
/// structure are directly used for the image's red, green and blue channel respectively.
/// Although alpha transparent <see cref="RGBQUAD"/> colors are
/// supported, the alpha channel of a 32-bit image never gets modified by this function.
/// A fill color with an alpha value smaller than 255 gets blended with the image's actual
/// background color, which is determined from the image's bottom-left pixel.
/// So, currently using alpha enabled colors, assumes the image to be unicolor before the
/// fill operation. However, the <see cref="RGBQUAD.rgbReserved"/> field is only taken into account,
/// if option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_RGBA"/> has been specified.
/// <para/>
/// For 16-bit images, the red-, green- and blue components of the specified color are
/// transparently translated into either the 16-bit 555 or 565 representation. This depends
/// on the image's actual red- green- and blue masks.
/// <para/>
/// Special attention must be payed for palletized images. Generally, the RGB color specified
/// is looked up in the image's palette. The found palette index is then used to fill the image.
/// There are some option flags, that affect this lookup process:
/// <list type="table">
/// <listheader>
/// <term>Value</term>
/// <description>Meaning</description>
/// </listheader>
/// <item>
/// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_DEFAULT"/></term>
/// <description>
/// Uses the color, that is nearest to the specified color.
/// This is the default behavior and should always find a
/// color in the palette. However, the visual result may
/// far from what was expected and mainly depends on the
/// image's palette.
/// </description>
/// </item>
/// <item>
/// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_EQUAL_COLOR"/></term>
/// <description>
/// Searches the image's palette for the specified color
/// but only uses the returned palette index, if the specified
/// color exactly matches the palette entry. Of course,
/// depending on the image's actual palette entries, this
/// operation may fail. In this case, the function falls back
/// to option <see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/>
/// and uses the RGBQUAD's rgbReserved member (or its low nibble for 4-bit images
/// or its least significant bit (LSB) for 1-bit images) as
/// the palette index used for the fill operation.
/// </description>
/// </item>
/// <item>
/// <term><see cref="FREE_IMAGE_COLOR_OPTIONS.FICO_ALPHA_IS_INDEX"/></term>
/// <description>
/// Does not perform any color lookup from the palette, but
/// uses the RGBQUAD's alpha channel member rgbReserved as
/// the palette index to be used for the fill operation.
/// However, for 4-bit images, only the low nibble of the
/// rgbReserved member are used and for 1-bit images, only
/// the least significant bit (LSB) is used.
/// </description>
/// </item>
/// </list>
/// </remarks>
public static bool FillBackground<T>(FIBITMAP dib, T color, FREE_IMAGE_COLOR_OPTIONS options)
where T : struct
{
if (dib.IsNull)
return false;
if (!CheckColorType(GetImageType(dib), color))
return false;
GCHandle handle = new GCHandle();
try
{
T[] buffer = new T[] { color };
handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
return FillBackground(dib, handle.AddrOfPinnedObject(), options);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
}
#endregion
#region Wrapper functions
/// <summary>
/// Returns the next higher possible color depth.
/// </summary>
/// <param name="bpp">Color depth to increase.</param>
/// <returns>The next higher color depth or 0 if there is no valid color depth.</returns>
internal static int GetNextColorDepth(int bpp)
{
int result = 0;
switch (bpp)
{
case 1:
result = 4;
break;
case 4:
result = 8;
break;
case 8:
result = 16;
break;
case 16:
result = 24;
break;
case 24:
result = 32;
break;
}
return result;
}
/// <summary>
/// Returns the next lower possible color depth.
/// </summary>
/// <param name="bpp">Color depth to decrease.</param>
/// <returns>The next lower color depth or 0 if there is no valid color depth.</returns>
internal static int GetPrevousColorDepth(int bpp)
{
int result = 0;
switch (bpp)
{
case 32:
result = 24;
break;
case 24:
result = 16;
break;
case 16:
result = 8;
break;
case 8:
result = 4;
break;
case 4:
result = 1;
break;
}
return result;
}
/// <summary>
/// Reads a null-terminated c-string.
/// </summary>
/// <param name="ptr">Pointer to the first char of the string.</param>
/// <returns>The converted string.</returns>
internal static unsafe string PtrToStr(byte* ptr)
{
string result = null;
if (ptr != null)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
while (*ptr != 0)
{
sb.Append((char)(*(ptr++)));
}
result = sb.ToString();
}
return result;
}
internal static unsafe byte[] CreateShrunkenPaletteLUT(FIBITMAP dib, out int uniqueColors)
{
byte[] result = null;
uniqueColors = 0;
if ((!dib.IsNull) && (GetImageType(dib) == FREE_IMAGE_TYPE.FIT_BITMAP) && (GetBPP(dib) <= 8))
{
int size = (int)GetColorsUsed(dib);
List<RGBQUAD> newPalette = new List<RGBQUAD>(size);
List<byte> lut = new List<byte>(size);
RGBQUAD* palette = (RGBQUAD*)GetPalette(dib);
RGBQUAD color;
int index;
for (int i = 0; i < size; i++)
{
color = palette[i];
color.rgbReserved = 255; // ignore alpha
index = newPalette.IndexOf(color);
if (index < 0)
{
newPalette.Add(color);
lut.Add((byte)(newPalette.Count - 1));
}
else
{
lut.Add((byte)index);
}
}
result = lut.ToArray();
uniqueColors = newPalette.Count;
}
return result;
}
internal static PropertyItem CreatePropertyItem()
{
return (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);
}
private static unsafe void CopyPalette(FIBITMAP src, FIBITMAP dst)
{
RGBQUAD* orgPal = (RGBQUAD*)GetPalette(src);
RGBQUAD* newPal = (RGBQUAD*)GetPalette(dst);
uint size = (uint)(sizeof(RGBQUAD) * GetColorsUsed(src));
CopyMemory(newPal, orgPal, size);
}
private static unsafe Scanline<FI4BIT>[] Get04BitScanlines(FIBITMAP dib)
{
int height = (int)GetHeight(dib);
Scanline<FI4BIT>[] array = new Scanline<FI4BIT>[height];
for (int i = 0; i < height; i++)
{
array[i] = new Scanline<FI4BIT>(dib, i);
}
return array;
}
/// <summary>
/// Changes a bitmaps color depth.
/// Used by SaveEx and SaveToStream.
/// </summary>
private static FIBITMAP PrepareBitmapColorDepth(FIBITMAP dibToSave, FREE_IMAGE_FORMAT format, FREE_IMAGE_COLOR_DEPTH colorDepth)
{
FREE_IMAGE_TYPE type = GetImageType(dibToSave);
if (type == FREE_IMAGE_TYPE.FIT_BITMAP)
{
int bpp = (int)GetBPP(dibToSave);
int targetBpp = (int)(colorDepth & FREE_IMAGE_COLOR_DEPTH.FICD_COLOR_MASK);
if (colorDepth != FREE_IMAGE_COLOR_DEPTH.FICD_AUTO)
{
// A fix colordepth was chosen
if (FIFSupportsExportBPP(format, targetBpp))
{
dibToSave = ConvertColorDepth(dibToSave, colorDepth, false);
}
else
{
throw new ArgumentException("FreeImage\n\nFreeImage Library plugin " +
GetFormatFromFIF(format) + " is unable to write images with a color depth of " +
targetBpp + " bpp.");
}
}
else
{
// Auto selection was chosen
if (!FIFSupportsExportBPP(format, bpp))
{
// The color depth is not supported
int bppUpper = bpp;
int bppLower = bpp;
// Check from the bitmaps current color depth in both directions
do
{
bppUpper = GetNextColorDepth(bppUpper);
if (FIFSupportsExportBPP(format, bppUpper))
{
dibToSave = ConvertColorDepth(dibToSave, (FREE_IMAGE_COLOR_DEPTH)bppUpper, false);
break;
}
bppLower = GetPrevousColorDepth(bppLower);
if (FIFSupportsExportBPP(format, bppLower))
{
dibToSave = ConvertColorDepth(dibToSave, (FREE_IMAGE_COLOR_DEPTH)bppLower, false);
break;
}
} while (!((bppLower == 0) && (bppUpper == 0)));
}
}
}
return dibToSave;
}
/// <summary>
/// Compares blocks of memory.
/// </summary>
/// <param name="buf1">A pointer to a block of memory to compare.</param>
/// <param name="buf2">A pointer to a block of memory to compare.</param>
/// <param name="length">Specifies the number of bytes to be compared.</param>
/// <returns>true, if all bytes compare as equal, false otherwise.</returns>
public static unsafe bool CompareMemory(void* buf1, void* buf2, uint length)
{
return (length == RtlCompareMemory(buf1, buf2, length));
}
/// <summary>
/// Compares blocks of memory.
/// </summary>
/// <param name="buf1">A pointer to a block of memory to compare.</param>
/// <param name="buf2">A pointer to a block of memory to compare.</param>
/// <param name="length">Specifies the number of bytes to be compared.</param>
/// <returns>true, if all bytes compare as equal, false otherwise.</returns>
public static unsafe bool CompareMemory(void* buf1, void* buf2, long length)
{
return (length == RtlCompareMemory(buf1, buf2, checked((uint)length)));
}
/// <summary>
/// Compares blocks of memory.
/// </summary>
/// <param name="buf1">A pointer to a block of memory to compare.</param>
/// <param name="buf2">A pointer to a block of memory to compare.</param>
/// <param name="length">Specifies the number of bytes to be compared.</param>
/// <returns>true, if all bytes compare as equal, false otherwise.</returns>
public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, uint length)
{
return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), length));
}
/// <summary>
/// Compares blocks of memory.
/// </summary>
/// <param name="buf1">A pointer to a block of memory to compare.</param>
/// <param name="buf2">A pointer to a block of memory to compare.</param>
/// <param name="length">Specifies the number of bytes to be compared.</param>
/// <returns>true, if all bytes compare as equal, false otherwise.</returns>
public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, long length)
{
return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), checked((uint)length)));
}
/// <summary>
/// Moves a block of memory from one location to another.
/// </summary>
/// <param name="dst">A pointer to the starting address of the move destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
/// <param name="size">The size of the block of memory to move, in bytes.</param>
public static unsafe void MoveMemory(void* dst, void* src, long size)
{
MoveMemory(dst, src, checked((uint)size));
}
/// <summary>
/// Moves a block of memory from one location to another.
/// </summary>
/// <param name="dst">A pointer to the starting address of the move destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
/// <param name="size">The size of the block of memory to move, in bytes.</param>
public static unsafe void MoveMemory(IntPtr dst, IntPtr src, uint size)
{
MoveMemory(dst.ToPointer(), src.ToPointer(), size);
}
/// <summary>
/// Moves a block of memory from one location to another.
/// </summary>
/// <param name="dst">A pointer to the starting address of the move destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to be moved.</param>
/// <param name="size">The size of the block of memory to move, in bytes.</param>
public static unsafe void MoveMemory(IntPtr dst, IntPtr src, long size)
{
MoveMemory(dst.ToPointer(), src.ToPointer(), checked((uint)size));
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, uint)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(byte* dest, byte* src, int len)
{
if (len >= 0x10)
{
do
{
*((int*)dest) = *((int*)src);
*((int*)(dest + 4)) = *((int*)(src + 4));
*((int*)(dest + 8)) = *((int*)(src + 8));
*((int*)(dest + 12)) = *((int*)(src + 12));
dest += 0x10;
src += 0x10;
}
while ((len -= 0x10) >= 0x10);
}
if (len > 0)
{
if ((len & 8) != 0)
{
*((int*)dest) = *((int*)src);
*((int*)(dest + 4)) = *((int*)(src + 4));
dest += 8;
src += 8;
}
if ((len & 4) != 0)
{
*((int*)dest) = *((int*)src);
dest += 4;
src += 4;
}
if ((len & 2) != 0)
{
*((short*)dest) = *((short*)src);
dest += 2;
src += 2;
}
if ((len & 1) != 0)
{
*dest = *src;
}
}
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, long)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(byte* dest, byte* src, long len)
{
CopyMemory(dest, src, checked((int)len));
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, long)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(void* dest, void* src, long len)
{
CopyMemory((byte*)dest, (byte*)src, checked((int)len));
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(void*, void*, uint)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(void* dest, void* src, int len)
{
CopyMemory((byte*)dest, (byte*)src, len);
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(IntPtr, IntPtr, uint)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int len)
{
CopyMemory((byte*)dest, (byte*)src, len);
}
/// <summary>
/// Copies a block of memory from one location to another.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
/// <remarks>
/// <b>CopyMemory</b> runs faster than <see cref="MoveMemory(IntPtr, IntPtr, long)"/>.
/// However, if both blocks overlap the result is undefined.
/// </remarks>
public static unsafe void CopyMemory(IntPtr dest, IntPtr src, long len)
{
CopyMemory((byte*)dest, (byte*)src, checked((int)len));
}
/// <summary>
/// Copies a block of memory into an array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, void* src, int len)
{
GCHandle handle = GCHandle.Alloc(dest, GCHandleType.Pinned);
try
{
CopyMemory((byte*)handle.AddrOfPinnedObject(), (byte*)src, len);
}
finally
{
handle.Free();
}
}
/// <summary>
/// Copies a block of memory into an array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, void* src, long len)
{
CopyMemory(dest, (byte*)src, checked((int)len));
}
/// <summary>
/// Copies a block of memory into an array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, IntPtr src, int len)
{
CopyMemory(dest, (byte*)src, len);
}
/// <summary>
/// Copies a block of memory into an array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">A pointer to the starting address of the block of memory to copy.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, IntPtr src, long len)
{
CopyMemory(dest, (byte*)src, checked((int)len));
}
/// <summary>
/// Copies the content of an array to a memory location.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(void* dest, Array src, int len)
{
GCHandle handle = GCHandle.Alloc(src, GCHandleType.Pinned);
try
{
CopyMemory((byte*)dest, (byte*)handle.AddrOfPinnedObject(), len);
}
finally
{
handle.Free();
}
}
/// <summary>
/// Copies the content of an array to a memory location.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(void* dest, Array src, long len)
{
CopyMemory((byte*)dest, src, checked((int)len));
}
/// <summary>
/// Copies the content of an array to a memory location.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(IntPtr dest, Array src, int len)
{
CopyMemory((byte*)dest, src, len);
}
/// <summary>
/// Copies the content of an array to a memory location.
/// </summary>
/// <param name="dest">A pointer to the starting address of the copied block's destination.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the block of memory to copy, in bytes.</param>
public static unsafe void CopyMemory(IntPtr dest, Array src, long len)
{
CopyMemory((byte*)dest, src, checked((int)len));
}
/// <summary>
/// Copies the content of one array into another array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the content to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, Array src, int len)
{
GCHandle dHandle = GCHandle.Alloc(dest, GCHandleType.Pinned);
try
{
GCHandle sHandle = GCHandle.Alloc(src, GCHandleType.Pinned);
try
{
CopyMemory((byte*)dHandle.AddrOfPinnedObject(), (byte*)sHandle.AddrOfPinnedObject(), len);
}
finally
{
sHandle.Free();
}
}
finally
{
dHandle.Free();
}
}
/// <summary>
/// Copies the content of one array into another array.
/// </summary>
/// <param name="dest">An array used as the destination of the copy process.</param>
/// <param name="src">An array used as the source of the copy process.</param>
/// <param name="len">The size of the content to copy, in bytes.</param>
public static unsafe void CopyMemory(Array dest, Array src, long len)
{
CopyMemory(dest, src, checked((int)len));
}
internal static string ColorToString(Color color)
{
return string.Format(
System.Globalization.CultureInfo.CurrentCulture,
"{{Name={0}, ARGB=({1}, {2}, {3}, {4})}}",
new object[] { color.Name, color.A, color.R, color.G, color.B });
}
internal static void Resize(ref string str, int length)
{
if ((str != null) && (length >= 0) && (str.Length != length))
{
char[] chars = str.ToCharArray();
Array.Resize(ref chars, length);
str = new string(chars);
}
}
internal static void Resize(ref string str, int min, int max)
{
if ((str != null) && (min >= 0) && (max >= 0) && (min <= max))
{
if (str.Length < min)
{
char[] chars = str.ToCharArray();
Array.Resize(ref chars, min);
str = new string(chars);
}
else if (str.Length > max)
{
char[] chars = str.ToCharArray();
Array.Resize(ref chars, max);
str = new string(chars);
}
}
}
internal static void Resize<T>(ref T[] array, int length)
{
if ((array != null) && (length >= 0) && (array.Length != length))
{
Array.Resize(ref array, length);
}
}
internal static void Resize<T>(ref T[] array, int min, int max)
{
if ((array != null) && (min >= 0) && (max >= 0) && (min <= max))
{
if (array.Length < min)
{
Array.Resize(ref array, min);
}
else if (array.Length > max)
{
Array.Resize(ref array, max);
}
}
}
internal static bool CheckColorType<T>(FREE_IMAGE_TYPE imageType, T color)
{
Type type = typeof(T);
bool result;
switch (imageType)
{
case FREE_IMAGE_TYPE.FIT_BITMAP:
result = (type == typeof(RGBQUAD)); break;
case FREE_IMAGE_TYPE.FIT_COMPLEX:
result = (type == typeof(FICOMPLEX)); break;
case FREE_IMAGE_TYPE.FIT_DOUBLE:
result = (type == typeof(double)); break;
case FREE_IMAGE_TYPE.FIT_FLOAT:
result = (type == typeof(float)); break;
case FREE_IMAGE_TYPE.FIT_INT16:
result = (type == typeof(Int16)); break;
case FREE_IMAGE_TYPE.FIT_INT32:
result = (type == typeof(Int32)); break;
case FREE_IMAGE_TYPE.FIT_RGB16:
result = (type == typeof(FIRGB16)); break;
case FREE_IMAGE_TYPE.FIT_RGBA16:
result = (type == typeof(FIRGBA16)); break;
case FREE_IMAGE_TYPE.FIT_RGBAF:
result = (type == typeof(FIRGBAF)); break;
case FREE_IMAGE_TYPE.FIT_RGBF:
result = (type == typeof(FIRGBF)); break;
case FREE_IMAGE_TYPE.FIT_UINT16:
result = (type == typeof(UInt16)); break;
case FREE_IMAGE_TYPE.FIT_UINT32:
result = (type == typeof(UInt32)); break;
default:
result = false; break;
}
return result;
}
#endregion
#region Dll-Imports
/// <summary>
/// Retrieves a handle to a display device context (DC) for the client area of a specified window
/// or for the entire screen. You can use the returned handle in subsequent GDI functions to draw in the DC.
/// </summary>
/// <param name="hWnd">Handle to the window whose DC is to be retrieved.
/// If this value is IntPtr.Zero, GetDC retrieves the DC for the entire screen. </param>
/// <returns>If the function succeeds, the return value is a handle to the DC for the specified window's client area.
/// If the function fails, the return value is NULL.</returns>
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
/// <summary>
/// Releases a device context (DC), freeing it for use by other applications.
/// The effect of the ReleaseDC function depends on the type of DC. It frees only common and window DCs.
/// It has no effect on class or private DCs.
/// </summary>
/// <param name="hWnd">Handle to the window whose DC is to be released.</param>
/// <param name="hDC">Handle to the DC to be released.</param>
/// <returns>Returns true on success, false on failure.</returns>
[DllImport("user32.dll")]
private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
/// <summary>
/// Creates a DIB that applications can write to directly.
/// The function gives you a pointer to the location of the bitmap bit values.
/// You can supply a handle to a file-mapping object that the function will use to create the bitmap,
/// or you can let the system allocate the memory for the bitmap.
/// </summary>
/// <param name="hdc">Handle to a device context.</param>
/// <param name="pbmi">Pointer to a BITMAPINFO structure that specifies various attributes of the DIB,
/// including the bitmap dimensions and colors.</param>
/// <param name="iUsage">Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure
/// pointed to by pbmi (either logical palette indexes or literal RGB values).</param>
/// <param name="ppvBits">Pointer to a variable that receives a pointer to the location of the DIB bit values.</param>
/// <param name="hSection">Handle to a file-mapping object that the function will use to create the DIB.
/// This parameter can be NULL.</param>
/// <param name="dwOffset">Specifies the offset from the beginning of the file-mapping object referenced by hSection
/// where storage for the bitmap bit values is to begin. This value is ignored if hSection is NULL.</param>
/// <returns>If the function succeeds, the return value is a handle to the newly created DIB,
/// and *ppvBits points to the bitmap bit values. If the function fails, the return value is NULL, and *ppvBits is NULL.</returns>
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBSection(
IntPtr hdc,
[In] IntPtr pbmi,
uint iUsage,
out IntPtr ppvBits,
IntPtr hSection,
uint dwOffset);
/// <summary>
/// Deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object.
/// After the object is deleted, the specified handle is no longer valid.
/// </summary>
/// <param name="hObject">Handle to a logical pen, brush, font, bitmap, region, or palette.</param>
/// <returns>Returns true on success, false on failure.</returns>
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
/// <summary>
/// Creates a compatible bitmap (DDB) from a DIB and, optionally, sets the bitmap bits.
/// </summary>
/// <param name="hdc">Handle to a device context.</param>
/// <param name="lpbmih">Pointer to a bitmap information header structure.</param>
/// <param name="fdwInit">Specifies how the system initializes the bitmap bits - (use 4).</param>
/// <param name="lpbInit">Pointer to an array of bytes containing the initial bitmap data.</param>
/// <param name="lpbmi">Pointer to a BITMAPINFO structure that describes the dimensions
/// and color format of the array pointed to by the lpbInit parameter.</param>
/// <param name="fuUsage">Specifies whether the bmiColors member of the BITMAPINFO structure
/// was initialized - (use 0).</param>
/// <returns>Handle to a DIB or null on failure.</returns>
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBitmap(
IntPtr hdc,
IntPtr lpbmih,
uint fdwInit,
IntPtr lpbInit,
IntPtr lpbmi,
uint fuUsage);
/// <summary>
/// Retrieves information for the specified graphics object.
/// </summary>
/// <param name="hgdiobj">Handle to the graphics object of interest.</param>
/// <param name="cbBuffer">Specifies the number of bytes of information to
/// be written to the buffer.</param>
/// <param name="lpvObject">Pointer to a buffer that receives the information
/// about the specified graphics object.</param>
/// <returns>0 on failure.</returns>
[DllImport("gdi32.dll")]
private static extern int GetObject(IntPtr hgdiobj, int cbBuffer, IntPtr lpvObject);
/// <summary>
/// Retrieves the bits of the specified compatible bitmap and copies them into a buffer
/// as a DIB using the specified format.
/// </summary>
/// <param name="hdc">Handle to the device context.</param>
/// <param name="hbmp">Handle to the bitmap. This must be a compatible bitmap (DDB).</param>
/// <param name="uStartScan">Specifies the first scan line to retrieve.</param>
/// <param name="cScanLines">Specifies the number of scan lines to retrieve.</param>
/// <param name="lpvBits">Pointer to a buffer to receive the bitmap data.</param>
/// <param name="lpbmi">Pointer to a BITMAPINFO structure that specifies the desired
/// format for the DIB data.</param>
/// <param name="uUsage">Specifies the format of the bmiColors member of the
/// BITMAPINFO structure - (use 0).</param>
/// <returns>0 on failure.</returns>
[DllImport("gdi32.dll")]
private static extern unsafe int GetDIBits(
IntPtr hdc,
IntPtr hbmp,
uint uStartScan,
uint cScanLines,
IntPtr lpvBits,
IntPtr lpbmi,
uint uUsage);
/// <summary>
/// Moves a block of memory from one location to another.
/// </summary>
/// <param name="dst">Pointer to the starting address of the move destination.</param>
/// <param name="src">Pointer to the starting address of the block of memory to be moved.</param>
/// <param name="size">Size of the block of memory to move, in bytes.</param>
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static unsafe extern void MoveMemory(void* dst, void* src, uint size);
/// <summary>
/// The RtlCompareMemory routine compares blocks of memory
/// and returns the number of bytes that are equivalent.
/// </summary>
/// <param name="buf1">A pointer to a block of memory to compare.</param>
/// <param name="buf2">A pointer to a block of memory to compare.</param>
/// <param name="count">Specifies the number of bytes to be compared.</param>
/// <returns>RtlCompareMemory returns the number of bytes that compare as equal.
/// If all bytes compare as equal, the input Length is returned.</returns>
[DllImport("ntdll.dll", EntryPoint = "RtlCompareMemory", SetLastError = false)]
internal static unsafe extern uint RtlCompareMemory(void* buf1, void* buf2, uint count);
#endregion
}
}