// ==========================================================
// 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
{
///
/// Static class importing functions from the FreeImage library
/// and providing additional functions.
///
public static partial class FreeImage
{
#region Constants
///
/// Array containing all 'FREE_IMAGE_MDMODEL's.
///
public static readonly FREE_IMAGE_MDMODEL[] FREE_IMAGE_MDMODELS =
(FREE_IMAGE_MDMODEL[])Enum.GetValues(typeof(FREE_IMAGE_MDMODEL));
///
/// Stores handles used to read from streams.
///
private static Dictionary streamHandles =
new Dictionary();
///
/// Version of the wrapper library.
///
private static Version WrapperVersion;
private const int DIB_RGB_COLORS = 0;
private const int DIB_PAL_COLORS = 1;
private const int CBM_INIT = 0x4;
///
/// An uncompressed format.
///
public const int BI_RGB = 0;
///
/// 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.
///
public const int BI_RLE8 = 1;
///
/// 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.
///
public const int BI_RLE4 = 2;
///
/// Specifies that the bitmap is not compressed and that the color table consists of three
/// DWORD 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.
///
public const int BI_BITFIELDS = 3;
///
/// Windows 98/Me, Windows 2000/XP: Indicates that the image is a JPEG image.
///
public const int BI_JPEG = 4;
///
/// Windows 98/Me, Windows 2000/XP: Indicates that the image is a PNG image.
///
public const int BI_PNG = 5;
#endregion
#region General functions
///
/// Returns the internal version of this FreeImage .NET wrapper.
///
/// The internal version of this FreeImage .NET wrapper.
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;
}
///
/// Returns the version of the native FreeImage library.
///
/// The version of the native FreeImage library.
public static Version GetNativeVersion()
{
return new Version(GetVersion());
}
///
/// Returns a value indicating if the FreeImage library is available or not.
/// See remarks for further details.
///
/// false if the file is not available or out of date;
/// true, otherwise.
///
/// 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 must be either in the same folder as the program's
/// executable or in a folder contained in the envirent variable PATH
/// (for example %WINDIR%\System32).
/// Further more must both libraries, including the program itself,
/// be the same architecture (x86 or x64).
///
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
///
/// Creates a new bitmap in memory.
///
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new Bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap
/// Handle to a FreeImage bitmap.
public static FIBITMAP Allocate(int width, int height, int bpp)
{
return Allocate(width, height, bpp, 0, 0, 0);
}
///
/// Creates a new bitmap in memory.
///
/// Type of the image.
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new Bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap
/// Handle to a FreeImage bitmap.
public static FIBITMAP AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp)
{
return AllocateT(type, width, height, bpp, 0, 0, 0);
}
///
/// 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.
///
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.
/// The color to fill the bitmap with or null.
/// Options to enable or disable function-features.
/// The palette of the bitmap or null.
/// Handle to a FreeImage bitmap.
///
/// This function is an extension to , 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.
///
/// Basically, this function internally relies on function , followed by a
/// call to . This is why both parameters
/// and behave the same as it is
/// documented for function .
/// So, please refer to the documentation of to
/// learn more about parameters and .
///
/// The palette specified through parameter 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 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.
///
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if is null.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// 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.
///
/// 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
/// is implicit, so the specified is applied to the palette entry,
/// specified by the background color's field.
/// The image is then filled with this palette index.
///
/// This function returns a newly created image as function does, if both
/// parameters and are null.
/// If only is null, the palette pointed to by
/// parameter is initially set for the new image, if a palletized
/// image of type 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.
///
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);
}
///
/// 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.
///
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmaps.
/// The color to fill the bitmap with or null.
/// Options to enable or disable function-features.
/// The palette of the bitmap or null.
/// Red part of the color layout.
/// eg: 0xFF0000
/// Green part of the color layout.
/// eg: 0x00FF00
/// Blue part of the color layout.
/// eg: 0x0000FF
/// Handle to a FreeImage bitmap.
///
/// This function is an extension to , 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.
///
/// Basically, this function internally relies on function , followed by a
/// call to . This is why both parameters
/// and behave the same as it is
/// documented for function .
/// So, please refer to the documentation of to
/// learn more about parameters and .
///
/// The palette specified through parameter 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 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.
///
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if is null.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// 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.
///
/// 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
/// is implicit, so the specified is applied to the palette entry,
/// specified by the background color's field.
/// The image is then filled with this palette index.
///
/// This function returns a newly created image as function does, if both
/// parameters and are null.
/// If only is null, the palette pointed to by
/// parameter is initially set for the new image, if a palletized
/// image of type 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.
///
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);
}
}
///
/// 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.
///
/// The type of the specified color.
/// Type of the image.
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap
/// The color to fill the bitmap with or null.
/// Options to enable or disable function-features.
/// The palette of the bitmap or null.
/// Handle to a FreeImage bitmap.
///
/// This function is an extension to , 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.
///
/// Basically, this function internally relies on function , followed by a
/// call to . This is why both parameters
/// and behave the same as it is
/// documented for function . So, please refer to the
/// documentation of to learn more about parameters color and options.
///
/// The palette specified through parameter palette is only copied to the newly created
/// image, if its image type is and the desired bit
/// depth is smaller than or equal to 8 bits per pixel. In other words, the
/// palette is only taken into account for palletized images. However, if the preceding conditions
/// match and if is not null, 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.
///
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if is null.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// 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.
///
/// 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
/// is implicit, so the specified color is applied to the palette entry, specified by the
/// background color's field. The image is then filled with
/// this palette index.
///
/// This function returns a newly created image as function does, if both
/// parameters and are null.
/// If only is null, the palette pointed to by
/// parameter is initially set for the new image, if a palletized
/// image of type 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.
///
public static FIBITMAP AllocateExT(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);
}
///
/// 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.
///
/// The type of the specified color.
/// Type of the image.
/// Width of the new bitmap.
/// Height of the new bitmap.
/// Bit depth of the new bitmap.
/// Supported pixel depth: 1-, 4-, 8-, 16-, 24-, 32-bit per pixel for standard bitmap
/// The color to fill the bitmap with or null.
/// Options to enable or disable function-features.
/// The palette of the bitmap or null.
/// Red part of the color layout.
/// eg: 0xFF0000
/// Green part of the color layout.
/// eg: 0x00FF00
/// Blue part of the color layout.
/// eg: 0x0000FF
/// Handle to a FreeImage bitmap.
///
/// This function is an extension to , 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.
///
/// Basically, this function internally relies on function , followed by a
/// call to . This is why both parameters
/// and behave the same as it is
/// documented for function . So, please refer to the
/// documentation of to learn more about parameters color and options.
///
/// The palette specified through parameter palette is only copied to the newly created
/// image, if its image type is and the desired bit
/// depth is smaller than or equal to 8 bits per pixel. In other words, the
/// palette is only taken into account for palletized images. However, if the preceding conditions
/// match and if is not null, 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.
///
/// However, specifying a palette is not necesarily needed, even for palletized images. This
/// function is capable of implicitly creating a palette, if is null.
/// If the specified background color is a greyscale value (red = green = blue) or if option
/// 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.
///
/// 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
/// is implicit, so the specified color is applied to the palette entry, specified by the
/// background color's field. The image is then filled with
/// this palette index.
///
/// This function returns a newly created image as function does, if both
/// parameters and are null.
/// If only is null, the palette pointed to by
/// parameter is initially set for the new image, if a palletized
/// image of type 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.
///
public static FIBITMAP AllocateExT(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);
}
}
///
/// Converts a FreeImage bitmap to a .NET .
///
/// Handle to a FreeImage bitmap.
/// The converted .NET .
/// Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.
///
/// is null.
///
/// The image type of is not FIT_BITMAP.
public static Bitmap GetBitmap(FIBITMAP dib)
{
return GetBitmap(dib, true);
}
///
/// Converts a FreeImage bitmap to a .NET .
///
/// Handle to a FreeImage bitmap.
/// When true existing metadata will be copied.
/// The converted .NET .
/// Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.
///
/// is null.
///
/// The image type of is not FIT_BITMAP.
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 list = new List();
// 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;
}
///
/// Converts an .NET into a FreeImage bitmap.
///
/// The to convert.
/// Handle to a FreeImage bitmap.
/// Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.
///
/// is null.
///
/// The bitmaps pixelformat is invalid.
public static FIBITMAP CreateFromBitmap(Bitmap bitmap)
{
return CreateFromBitmap(bitmap, false);
}
///
/// Converts an .NET into a FreeImage bitmap.
///
/// The to convert.
/// When true existing metadata will be copied.
/// Handle to a FreeImage bitmap.
/// Copying metadata has been disabled until a proper way
/// of reading and storing metadata in a .NET bitmap is found.
///
/// is null.
///
/// The bitmaps pixelformat is invalid.
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;
}
///
/// Converts a raw bitmap to a FreeImage bitmap.
///
/// Array of bytes containing the raw bitmap.
/// The type of the raw bitmap.
/// The width in pixels of the raw bitmap.
/// The height in pixels of the raw bitmap.
/// Defines the total width of a scanline in the raw bitmap,
/// including padding bytes.
/// The bit depth (bits per pixel) of the raw bitmap.
/// 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.
/// 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.
/// 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.
/// 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.
/// Handle to a FreeImage bitmap.
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);
}
}
///
/// Converts a raw bitmap to a FreeImage bitmap.
///
/// Pointer to the memory block containing the raw bitmap.
/// The type of the raw bitmap.
/// The width in pixels of the raw bitmap.
/// The height in pixels of the raw bitmap.
/// Defines the total width of a scanline in the raw bitmap,
/// including padding bytes.
/// The bit depth (bits per pixel) of the raw bitmap.
/// 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.
/// 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.
/// 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.
/// 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.
/// Handle to a FreeImage bitmap.
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;
}
///
/// Saves a .NET to a file.
///
/// The .NET to save.
/// Name of the file to save to.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// The bitmaps pixelformat is invalid.
public static bool SaveBitmap(Bitmap bitmap, string filename)
{
return SaveBitmap(
bitmap,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
FREE_IMAGE_SAVE_FLAGS.DEFAULT);
}
///
/// Saves a .NET to a file.
///
/// The .NET to save.
/// Name of the file to save to.
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// The bitmaps pixelformat is invalid.
public static bool SaveBitmap(Bitmap bitmap, string filename, FREE_IMAGE_SAVE_FLAGS flags)
{
return SaveBitmap(
bitmap,
filename,
FREE_IMAGE_FORMAT.FIF_UNKNOWN,
flags);
}
///
/// Saves a .NET to a file.
///
/// The .NET to save.
/// Name of the file to save to.
/// Format of the bitmap. If the format should be taken from the
/// filename use .
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// The bitmaps pixelformat is invalid.
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;
}
///
/// Loads a FreeImage bitmap.
/// The file will be loaded with default loading flags.
///
/// The complete name of the file to load.
/// Handle to a FreeImage bitmap.
///
/// does not exists.
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);
}
///
/// Loads a FreeImage bitmap.
/// Load flags can be provided by the flags parameter.
///
/// The complete name of the file to load.
/// Flags to enable or disable plugin-features.
/// Handle to a FreeImage bitmap.
///
/// does not exists.
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);
}
///
/// Loads a FreeImage bitmap.
/// In case the loading format is the files
/// real format is being analysed. If no plugin can read the file, format remains
/// and 0 is returned.
/// The file will be loaded with default loading flags.
///
/// The complete name of the file to load.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadEx it will be returned in format.
/// Handle to a FreeImage bitmap.
///
/// does not exists.
public static FIBITMAP LoadEx(string filename, ref FREE_IMAGE_FORMAT format)
{
return LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
///
/// Loads a FreeImage bitmap.
/// In case the loading format is the files
/// real format is being analysed. If no plugin can read the file, format remains
/// and 0 is returned.
/// Load flags can be provided by the flags parameter.
///
/// The complete name of the file to load.
/// Flags to enable or disable plugin-features.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadEx it will be returned in format.
///
/// Handle to a FreeImage bitmap.
///
/// does not exists.
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;
}
///
/// Loads a .NET from a file.
///
/// Name of the file to be loaded.
/// Format of the image. If the format should be taken from the
/// filename use .
/// Flags to enable or disable plugin-features.
/// The loaded .NET .
///
/// does not exists.
///
/// The image type of the image is not .
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;
}
///
/// Deletes a previously loaded FreeImage bitmap from memory and resets the handle to 0.
///
/// Handle to a FreeImage bitmap.
public static void UnloadEx(ref FIBITMAP dib)
{
if (!dib.IsNull)
{
Unload(dib);
dib.SetNull();
}
}
///
/// 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.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Format of the image. If the format should be taken from the
/// filename use .
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// 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.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// 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.
///
/// Handle to a FreeImage bitmap.
/// 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
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// 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.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Flags to enable or disable plugin-features.
/// When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is
/// the format is taken off the filename.
/// If no suitable format was found false will be returned.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Format of the image. If the format should be taken from the
/// filename use .
/// When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is
/// 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.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Format of the image. If the format should be taken from the
/// filename use .
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
///
/// or is null.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a file.
/// In case the loading format is
/// 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 a suitable color depth
/// will be taken if available.
///
/// Handle to a FreeImage bitmap.
/// 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.
/// Format of the image. If the format should be taken from the
/// filename use .
/// Flags to enable or disable plugin-features.
/// The new color depth of the bitmap.
/// Set to 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.
/// When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.
/// Returns true on success, false on failure.
///
/// A direct color conversion failed.
///
/// or is null.
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;
}
///
/// Loads a FreeImage bitmap.
/// The stream must be set to the correct position before calling LoadFromStream.
///
/// The stream to read from.
/// Handle to a FreeImage bitmap.
///
/// is null.
///
/// is not capable of reading.
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);
}
///
/// Loads a FreeImage bitmap.
/// The stream must be set to the correct position before calling LoadFromStream.
///
/// The stream to read from.
/// Flags to enable or disable plugin-features.
/// Handle to a FreeImage bitmap.
///
/// is null.
///
/// is not capable of reading.
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);
}
///
/// Loads a FreeImage bitmap.
/// In case the loading format is the
/// bitmaps real format is being analysed.
/// The stream must be set to the correct position before calling LoadFromStream.
///
/// The stream to read from.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadFromStream it will be returned in format.
/// Handle to a FreeImage bitmap.
///
/// is null.
///
/// is not capable of reading.
public static FIBITMAP LoadFromStream(Stream stream, ref FREE_IMAGE_FORMAT format)
{
return LoadFromStream(stream, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);
}
///
/// Loads a FreeImage bitmap.
/// In case the loading format is
/// the bitmaps real format is being analysed.
/// The stream must be set to the correct position before calling LoadFromStream.
///
/// The stream to read from.
/// Flags to enable or disable plugin-features.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadFromStream it will be returned in format.
/// Handle to a FreeImage bitmap.
///
/// is null.
///
/// is not capable of reading.
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);
}
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// When true the structure will be unloaded on success.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// Flags to enable or disable plugin-features.
/// When true the structure will be unloaded on success.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// Flags to enable or disable plugin-features.
/// The new color depth of the bitmap.
/// Set to 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.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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);
}
///
/// Saves a previously loaded FreeImage bitmap to a stream.
/// The stream must be set to the correct position before calling SaveToStream.
///
/// Handle to a FreeImage bitmap.
/// The stream to write to.
/// Format of the image.
/// Flags to enable or disable plugin-features.
/// The new color depth of the bitmap.
/// Set to 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.
/// When true the structure will be unloaded on success.
/// Returns true on success, false on failure.
///
/// or is null.
///
/// cannot write.
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
///
/// Checks if an extension is valid for a certain format.
///
/// The desired format.
/// The desired extension.
/// True if the extension is valid for the given format, false otherwise.
///
/// is null.
public static bool IsExtensionValidForFIF(FREE_IMAGE_FORMAT fif, string extension)
{
return IsExtensionValidForFIF(fif, extension, StringComparison.CurrentCultureIgnoreCase);
}
///
/// Checks if an extension is valid for a certain format.
///
/// The desired format.
/// The desired extension.
/// The string comparison type.
/// True if the extension is valid for the given format, false otherwise.
///
/// is null.
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;
}
///
/// Checks if a filename is valid for a certain format.
///
/// The desired format.
/// The desired filename.
/// True if the filename is valid for the given format, false otherwise.
///
/// is null.
public static bool IsFilenameValidForFIF(FREE_IMAGE_FORMAT fif, string filename)
{
return IsFilenameValidForFIF(fif, filename, StringComparison.CurrentCultureIgnoreCase);
}
///
/// Checks if a filename is valid for a certain format.
///
/// The desired format.
/// The desired filename.
/// The string comparison type.
/// True if the filename is valid for the given format, false otherwise.
///
/// is null.
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;
}
///
/// 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.
/// The image format to obtain the primary extension for.
/// The primary extension of the specified image format.
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
///
/// Loads a FreeImage multi-paged bitmap.
///
/// The complete name of the file to load.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
///
/// The complete name of the file to load.
/// When true performance is increased at the cost of memory.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
///
/// The complete name of the file to load.
/// When true the bitmap will be loaded read only.
/// When true performance is increased at the cost of memory.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
///
/// The complete name of the file to load.
/// When true a new bitmap is created.
/// When true the bitmap will be loaded read only.
/// When true performance is increased at the cost of memory.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is the files real
/// format is being analysed. If no plugin can read the file, format remains
/// and 0 is returned.
///
/// The complete name of the file to load.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadEx it will be returned in format.
/// When true a new bitmap is created.
/// When true the bitmap will be loaded read only.
/// When true performance is increased at the cost of memory.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is the files
/// real format is being analysed. If no plugin can read the file, format remains
/// and 0 is returned.
/// Load flags can be provided by the flags parameter.
///
/// The complete name of the file to load.
/// Format of the image. If the format is unknown use
/// .
/// In case a suitable format was found by LoadEx it will be returned in format.
/// Flags to enable or disable plugin-features.
/// When true a new bitmap is created.
/// When true the bitmap will be loaded read only.
/// When true performance is increased at the cost of memory.
/// Handle to a FreeImage multi-paged bitmap.
///
/// does not exists while opening.
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;
}
///
/// Loads a FreeImage multi-paged bitmap.
///
/// The stream to load the bitmap from.
/// Handle to a FreeImage multi-paged bitmap.
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);
}
///
/// Loads a FreeImage multi-paged bitmap.
/// In case the loading format is the files
/// real format is being analysed. If no plugin can read the file, format remains
/// and 0 is returned.
/// Load flags can be provided by the flags parameter.
///
/// The stream to load the bitmap from.
/// Format of the image. If the format is unknown use
/// .
/// Flags to enable or disable plugin-features.
/// Handle to a FreeImage multi-paged bitmap.
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;
}
}
///
/// Closes a previously opened multi-page bitmap and, when the bitmap was not opened read-only, applies any changes made to it.
///
/// Handle to a FreeImage multi-paged bitmap.
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
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;
}
///
/// 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.
///
/// Handle to a FreeImage multi-paged bitmap.
/// Returns true on success, false on failure.
public static bool CloseMultiBitmapEx(ref FIMULTIBITMAP bitmap)
{
return CloseMultiBitmapEx(ref bitmap, FREE_IMAGE_SAVE_FLAGS.DEFAULT);
}
///
/// 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.
///
/// Handle to a FreeImage multi-paged bitmap.
/// Flags to enable or disable plugin-features.
/// Returns true on success, false on failure.
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;
}
///
/// Retrieves the number of pages that are locked in a multi-paged bitmap.
///
/// Handle to a FreeImage multi-paged bitmap.
/// Number of locked pages.
///
/// is null.
public static int GetLockedPageCount(FIMULTIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
int result = 0;
GetLockedPageNumbers(dib, null, ref result);
return result;
}
///
/// Retrieves a list locked pages of a multi-paged bitmap.
///
/// Handle to a FreeImage multi-paged bitmap.
/// List containing the indexes of the locked pages.
///
/// is null.
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;
}
///
/// 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
/// ,
/// ,
/// or
/// .
///
/// The stream to read from.
/// Format of the image.
/// Flags to enable or disable plugin-features.
/// The temporary memory buffer used to load the bitmap.
/// Handle to a FreeImage multi-paged bitmap.
///
/// is null.
///
/// can not read.
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
///
/// 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.
///
/// Name of the stream to analyze.
/// Type of the bitmap.
///
/// is null.
///
/// can not read.
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
///
/// Retrieves an hBitmap for a FreeImage bitmap.
/// Call FreeHbitmap(IntPtr) to free the handle.
///
/// Handle to a FreeImage bitmap.
/// A reference device context.
/// Use IntPtr.Zero if no reference is available.
/// When true dib will be unloaded if the function succeeded.
/// The hBitmap for the FreeImage bitmap.
///
/// is null.
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;
}
///
/// Returns an HBITMAP created by the CreateDIBitmap() function which in turn
/// has always the same color depth as the reference DC, which may be provided
/// through . The desktop DC will be used,
/// if IntPtr.Zero DC is specified.
/// Call to free the handle.
///
/// Handle to a FreeImage bitmap.
/// Handle to a device context.
/// When true the structure will be unloaded on success.
/// If the function failed and returned false, the bitmap was not unloaded.
/// If the function succeeds, the return value is a handle to the
/// compatible bitmap. If the function fails, the return value is .
///
/// is null.
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;
}
///
/// Creates a FreeImage DIB from a Device Context/Compatible Bitmap.
///
/// Handle to the bitmap.
/// Handle to a device context.
/// Handle to a FreeImage bitmap.
///
/// is null.
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;
}
///
/// Frees a bitmap handle.
///
/// Handle to a bitmap.
/// True on success, false on failure.
public static bool FreeHbitmap(IntPtr hbitmap)
{
return DeleteObject(hbitmap);
}
#endregion
#region Bitmap information functions
///
/// Retrieves a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
///
/// Handle to a FreeImage bitmap.
/// The resolution in 'dots per inch'.
///
/// is null.
public static uint GetResolutionX(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return (uint)(0.5d + 0.0254d * GetDotsPerMeterX(dib));
}
///
/// Retrieves a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
///
/// Handle to a FreeImage bitmap.
/// The resolution in 'dots per inch'.
///
/// is null.
public static uint GetResolutionY(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return (uint)(0.5d + 0.0254d * GetDotsPerMeterY(dib));
}
///
/// Sets a DIB's resolution in X-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
///
/// Handle to a FreeImage bitmap.
/// The new resolution in 'dots per inch'.
///
/// is null.
public static void SetResolutionX(FIBITMAP dib, uint res)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
SetDotsPerMeterX(dib, (uint)((double)res / 0.0254d + 0.5d));
}
///
/// Sets a DIB's resolution in Y-direction measured in 'dots per inch' (DPI) and not in
/// 'dots per meter'.
///
/// Handle to a FreeImage bitmap.
/// The new resolution in 'dots per inch'.
///
/// is null.
public static void SetResolutionY(FIBITMAP dib, uint res)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
SetDotsPerMeterY(dib, (uint)((double)res / 0.0254d + 0.5d));
}
///
/// 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.
///
/// Handle to a FreeImage bitmap.
/// True if the image is a greyscale image, else false.
///
/// is null.
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;
}
///
/// Returns a structure that represents the palette of a FreeImage bitmap.
///
/// Handle to a FreeImage bitmap.
/// A structure representing the bitmaps palette.
///
/// is null.
public static Palette GetPaletteEx(FIBITMAP dib)
{
return new Palette(dib);
}
///
/// Returns the structure of a FreeImage bitmap.
/// The structure is a copy, so changes will have no effect on
/// the bitmap itself.
///
/// Handle to a FreeImage bitmap.
/// structure of the bitmap.
///
/// is null.
public static unsafe BITMAPINFOHEADER GetInfoHeaderEx(FIBITMAP dib)
{
if (dib.IsNull)
{
throw new ArgumentNullException("dib");
}
return *(BITMAPINFOHEADER*)GetInfoHeader(dib);
}
///
/// Returns the structure of a FreeImage bitmap.
/// The structure is a copy, so changes will have no effect on
/// the bitmap itself.
///
/// Handle to a FreeImage bitmap.
/// structure of the bitmap.
///
/// is null.
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(ptr, (int)result.bmiHeader.biClrUsed).Data;
}
return result;
}
///
/// Returns the pixelformat of the bitmap.
///
/// Handle to a FreeImage bitmap.
/// of the bitmap.
///
/// is null.
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;
}
///
/// Retrieves all parameters needed to create a new FreeImage bitmap from
/// the format of a .NET .
///
/// The
/// of the .NET .
/// Returns the type used for the new bitmap.
/// Returns the color depth for the new bitmap.
/// Returns the red_mask for the new bitmap.
/// Returns the green_mask for the new bitmap.
/// Returns the blue_mask for the new bitmap.
/// True in case a matching conversion exists; else false.
///
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;
}
///
/// Returns the for the specified
/// .
///
/// The
/// for which to return the corresponding .
/// The for the specified
///
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;
}
///
/// Retrieves all parameters needed to create a new FreeImage bitmap from
/// raw bits .
///
/// The
/// of the data in memory.
/// The color depth for the data.
/// Returns the red_mask for the data.
/// Returns the green_mask for the data.
/// Returns the blue_mask for the data.
/// True in case a matching conversion exists; else false.
///
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;
}
///
/// Compares two FreeImage bitmaps.
///
/// The first bitmap to compare.
/// The second bitmap to compare.
/// Determines which components of the bitmaps will be compared.
/// True in case both bitmaps match the compare conditions, false otherwise.
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;
}
///
/// Returns the FreeImage bitmap's transparency table.
/// The array is empty in case the bitmap has no transparency table.
///
/// Handle to a FreeImage bitmap.
/// The FreeImage bitmap's transparency table.
///
/// is null.
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;
}
///
/// Set the FreeImage bitmap's transparency table. Only affects palletised bitmaps.
///
/// Handle to a FreeImage bitmap.
/// The FreeImage bitmap's new transparency table.
///
/// or is null.
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);
}
///
/// 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
/// type images only.
///
/// Handle to a FreeImage bitmap.
/// Returns the number of unique colors used by the image specified or
/// zero, if the image type cannot be handled.
///
/// is null.
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;
}
///
/// Verifies whether the FreeImage bitmap is 16bit 555.
///
/// The FreeImage bitmap to verify.
/// true if the bitmap is RGB16-555; otherwise false.
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));
}
///
/// Verifies whether the FreeImage bitmap is 16bit 565.
///
/// The FreeImage bitmap to verify.
/// true if the bitmap is RGB16-565; otherwise false.
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
///
/// Creates a new ICC-Profile for a FreeImage bitmap.
///
/// Handle to a FreeImage bitmap.
/// The data of the new ICC-Profile.
/// The new ICC-Profile of the bitmap.
///
/// is null.
public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data)
{
return new FIICCPROFILE(dib, data);
}
///
/// Creates a new ICC-Profile for a FreeImage bitmap.
///
/// Handle to a FreeImage bitmap.
/// The data of the new ICC-Profile.
/// The number of bytes of to use.
/// The new ICC-Profile of the FreeImage bitmap.
///
/// is null.
public static FIICCPROFILE CreateICCProfileEx(FIBITMAP dib, byte[] data, int size)
{
return new FIICCPROFILE(dib, data, size);
}
#endregion
#region Conversion functions
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// When true the structure will be unloaded on success.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Threshold value when converting with
/// .
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Dither algorithm when converting
/// with .
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// The quantization algorithm for conversion to 8-bit color depth.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Threshold value when converting with
/// .
/// When true the structure will be unloaded on success.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Dither algorithm when converting with
/// .
/// When true the structure will be unloaded on success.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// The quantization algorithm for conversion to 8-bit color depth.
/// When true the structure will be unloaded on success.
/// Handle to a FreeImage bitmap.
///
/// is null.
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);
}
///
/// Converts a FreeImage bitmap from one color depth to another.
/// If the conversion fails the original FreeImage bitmap is returned.
///
/// Handle to a FreeImage bitmap.
/// The desired output format.
/// Threshold value when converting with
/// .
/// Dither algorithm when converting with
/// .
/// The quantization algorithm for conversion to 8-bit color depth.
/// When true the structure will be unloaded on success.
/// Handle to a FreeImage bitmap.
///
/// is null.
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;
}
///
/// ColorQuantizeEx is an extension to the
/// 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.
///
/// Handle to a FreeImage bitmap.
/// Specifies the color reduction algorithm to be used.
/// Size of the desired output palette.
/// The provided palette.
/// true to create a bitmap with the smallest possible
/// color depth for the specified .
/// Handle to a FreeImage bitmap.
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;
}
///
/// ColorQuantizeEx is an extension to the
/// 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.
///
/// Handle to a FreeImage bitmap.
/// Specifies the color reduction algorithm to be used.
/// Size of the desired output palette.
/// The provided palette.
/// The desired color depth of the created image.
/// Handle to a FreeImage bitmap.
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 srcScanline = new Scanline(temp, y);
Scanline dstScanline = new Scanline(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 srcScanline = new Scanline(temp, y);
Scanline dstScanline = new Scanline(result, y);
for (int x = (int)GetWidth(temp) - 1; x >= 0; x--)
{
dstScanline[x] = srcScanline[x];
}
}
}
}
UnloadEx(ref temp);
return result;
}
}
#endregion
#region Metadata
///
/// Copies metadata from one FreeImage bitmap to another.
///
/// Source FreeImage bitmap containing the metadata.
/// FreeImage bitmap to copy the metadata to.
/// Flags to switch different copy modes.
/// Returns -1 on failure else the number of copied tags.
///
/// or is null.
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;
}
///
/// Returns the comment of a JPEG, PNG or GIF image.
///
/// Handle to a FreeImage bitmap.
/// Comment of the FreeImage bitmp, or null in case no comment exists.
///
/// is null.
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;
}
///
/// Sets the comment of a JPEG, PNG or GIF image.
///
/// Handle to a FreeImage bitmap.
/// New comment of the FreeImage bitmap.
/// Use null to remove the comment.
/// Returns true on success, false on failure.
///
/// is null.
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;
}
///
/// Retrieve a metadata attached to a FreeImage bitmap.
///
/// The metadata model to look for.
/// Handle to a FreeImage bitmap.
/// The metadata field name.
/// A structure returned by the function.
/// Returns true on success, false on failure.
///
/// is null.
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;
}
///
/// Attach a new metadata tag to a FreeImage bitmap.
///
/// The metadata model used to store the tag.
/// Handle to a FreeImage bitmap.
/// The tag field name.
/// The to be attached.
/// Returns true on success, false on failure.
///
/// is null.
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);
}
///
/// Provides information about the first instance of a tag that matches the metadata model.
///
/// The model to match.
/// Handle to a FreeImage bitmap.
/// Tag that matches the metadata model.
/// Unique search handle that can be used to call FindNextMetadata or FindCloseMetadata.
/// Null if the metadata model does not exist.
///
/// is null.
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;
}
///
/// 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.
///
/// Unique search handle provided by FindFirstMetadata.
/// Tag that matches the metadata model.
/// Returns true on success, false on failure.
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;
}
///
/// Closes the specified metadata search handle and releases associated resources.
///
/// The handle to close.
public static void FindCloseMetadata(FIMETADATA mdhandle)
{
if (metaDataSearchHandler.ContainsKey(mdhandle))
{
metaDataSearchHandler.Remove(mdhandle);
}
FindCloseMetadata_(mdhandle);
}
///
/// This dictionary links FIMETADATA handles and FREE_IMAGE_MDMODEL models.
///
private static Dictionary metaDataSearchHandler
= new Dictionary(1);
#endregion
#region Rotation and Flipping
///
/// 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°.
/// null is returned for other values.
///
/// Handle to a FreeImage bitmap.
/// The angle of rotation.
/// Handle to a FreeImage bitmap.
public static FIBITMAP Rotate(FIBITMAP dib, double angle)
{
return Rotate(dib, angle, IntPtr.Zero);
}
///
/// 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°.
/// null is returned for other values.
///
/// The type of the color to use as background.
/// Handle to a FreeImage bitmap.
/// The angle of rotation.
/// The color used used to fill the bitmap's background.
/// Handle to a FreeImage bitmap.
public static FIBITMAP Rotate(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);
}
}
///
/// Rotates a 4-bit color FreeImage bitmap.
/// Allowed values for are 90, 180 and 270.
/// In case is 0 or 360 a clone is returned.
/// 0 is returned for other values or in case the rotation fails.
///
/// Handle to a FreeImage bitmap.
/// The angle of rotation.
/// Handle to a FreeImage bitmap.
///
/// This function is kind of temporary due to FreeImage's lack of
/// rotating 4-bit images. It's particularly used by 's
/// method RotateFlip. This function will be removed as soon as FreeImage
/// supports rotating 4-bit images.
///
///
/// is null.
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[] 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
///
/// Enlarges or shrinks the FreeImage bitmap selectively per side and fills newly added areas
/// with the specified background color. See remarks for further details.
///
/// The type of the specified color.
/// Handle to a FreeImage bitmap.
/// The number of pixels, the image should be enlarged on its left side.
/// Negative values shrink the image on its left side.
/// The number of pixels, the image should be enlarged on its top side.
/// Negative values shrink the image on its top side.
/// The number of pixels, the image should be enlarged on its right side.
/// Negative values shrink the image on its right side.
/// The number of pixels, the image should be enlarged on its bottom side.
/// Negative values shrink the image on its bottom side.
/// The color, the enlarged sides of the image should be filled with.
/// Options that affect the color search process for palletized images.
/// Handle to a FreeImage bitmap.
///
/// 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 , ,
/// or . This value represents the border's
/// width in pixels. Newly created parts of the image (the border areas) are filled with the
/// specified .
/// 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.
///
/// So, calling this function with all parameters , ,
/// and set to zero, is
/// effectively the same as calling function ; setting all parameters
/// , , and
/// to value equal to or smaller than zero, my easily be substituted
/// by a call to function . Both these cases produce a new image, which is
/// guaranteed not to be larger than the input image. Thus, since the specified
/// is not needed in these cases,
/// may be null.
///
/// Both parameters and work according to
/// function . So, please refer to the documentation of
/// to learn more about parameters
/// and . 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.
///
///
/// // create a white color
/// RGBQUAD c;
/// c.rgbRed = 0xFF;
/// c.rgbGreen = 0xFF;
/// c.rgbBlue = 0xFF;
/// c.rgbReserved = 0x00;
///
/// // add a white, symmetric 10 pixel wide border to the image
/// dib2 = FreeImage_EnlargeCanvas(dib, 10, 10, 10, 10, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);
///
/// // add white, 20 pixel wide stripes to the top and bottom side of the image
/// dib3 = FreeImage_EnlargeCanvas(dib, 0, 20, 0, 20, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);
///
/// // add white, 30 pixel wide stripes to the right side of the image and
/// // cut off the 40 leftmost pixel columns
/// dib3 = FreeImage_EnlargeCanvas(dib, -40, 0, 30, 0, c, FREE_IMAGE_COLOR_OPTIONS.FICO_RGB);
///
public static FIBITMAP EnlargeCanvas(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
///
/// Sets all pixels of the specified image to the color provided through the
/// parameter. See remarks for further details.
///
/// The type of the specified color.
/// Handle to a FreeImage bitmap.
/// The color to fill the bitmap with. See remarks for further details.
/// Options that affect the color search process for palletized images.
/// true on success, false on failure.
///
/// This function sets all pixels of an image to the color provided through
/// the parameter. is used for standard type images.
/// For non standard type images the underlaying structure is used.
///
/// So, must be of type , if the image to be filled is of type
/// and must be a structure if the
/// image is of type and so on.
///
/// However, the fill color is always specified through a structure
/// for all images of type .
/// So, for 32- and 24-bit images, the red, green and blue members of the
/// structure are directly used for the image's red, green and blue channel respectively.
/// Although alpha transparent 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 field is only taken into account,
/// if option has been specified.
///
/// 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.
///
/// 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:
///
///
/// Value
/// Meaning
///
/// -
///
///
/// 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.
///
///
/// -
///
///
/// 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
/// 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.
///
///
/// -
///
///
/// 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.
///
///
///
///
public static bool FillBackground(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
///
/// Returns the next higher possible color depth.
///
/// Color depth to increase.
/// The next higher color depth or 0 if there is no valid color depth.
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;
}
///
/// Returns the next lower possible color depth.
///
/// Color depth to decrease.
/// The next lower color depth or 0 if there is no valid color depth.
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;
}
///
/// Reads a null-terminated c-string.
///
/// Pointer to the first char of the string.
/// The converted string.
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 newPalette = new List(size);
List lut = new List(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[] Get04BitScanlines(FIBITMAP dib)
{
int height = (int)GetHeight(dib);
Scanline[] array = new Scanline[height];
for (int i = 0; i < height; i++)
{
array[i] = new Scanline(dib, i);
}
return array;
}
///
/// Changes a bitmaps color depth.
/// Used by SaveEx and SaveToStream.
///
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;
}
///
/// Compares blocks of memory.
///
/// A pointer to a block of memory to compare.
/// A pointer to a block of memory to compare.
/// Specifies the number of bytes to be compared.
/// true, if all bytes compare as equal, false otherwise.
public static unsafe bool CompareMemory(void* buf1, void* buf2, uint length)
{
return (length == RtlCompareMemory(buf1, buf2, length));
}
///
/// Compares blocks of memory.
///
/// A pointer to a block of memory to compare.
/// A pointer to a block of memory to compare.
/// Specifies the number of bytes to be compared.
/// true, if all bytes compare as equal, false otherwise.
public static unsafe bool CompareMemory(void* buf1, void* buf2, long length)
{
return (length == RtlCompareMemory(buf1, buf2, checked((uint)length)));
}
///
/// Compares blocks of memory.
///
/// A pointer to a block of memory to compare.
/// A pointer to a block of memory to compare.
/// Specifies the number of bytes to be compared.
/// true, if all bytes compare as equal, false otherwise.
public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, uint length)
{
return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), length));
}
///
/// Compares blocks of memory.
///
/// A pointer to a block of memory to compare.
/// A pointer to a block of memory to compare.
/// Specifies the number of bytes to be compared.
/// true, if all bytes compare as equal, false otherwise.
public static unsafe bool CompareMemory(IntPtr buf1, IntPtr buf2, long length)
{
return (length == RtlCompareMemory(buf1.ToPointer(), buf2.ToPointer(), checked((uint)length)));
}
///
/// Moves a block of memory from one location to another.
///
/// A pointer to the starting address of the move destination.
/// A pointer to the starting address of the block of memory to be moved.
/// The size of the block of memory to move, in bytes.
public static unsafe void MoveMemory(void* dst, void* src, long size)
{
MoveMemory(dst, src, checked((uint)size));
}
///
/// Moves a block of memory from one location to another.
///
/// A pointer to the starting address of the move destination.
/// A pointer to the starting address of the block of memory to be moved.
/// The size of the block of memory to move, in bytes.
public static unsafe void MoveMemory(IntPtr dst, IntPtr src, uint size)
{
MoveMemory(dst.ToPointer(), src.ToPointer(), size);
}
///
/// Moves a block of memory from one location to another.
///
/// A pointer to the starting address of the move destination.
/// A pointer to the starting address of the block of memory to be moved.
/// The size of the block of memory to move, in bytes.
public static unsafe void MoveMemory(IntPtr dst, IntPtr src, long size)
{
MoveMemory(dst.ToPointer(), src.ToPointer(), checked((uint)size));
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
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;
}
}
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
public static unsafe void CopyMemory(byte* dest, byte* src, long len)
{
CopyMemory(dest, src, checked((int)len));
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
public static unsafe void CopyMemory(void* dest, void* src, long len)
{
CopyMemory((byte*)dest, (byte*)src, checked((int)len));
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
public static unsafe void CopyMemory(void* dest, void* src, int len)
{
CopyMemory((byte*)dest, (byte*)src, len);
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int len)
{
CopyMemory((byte*)dest, (byte*)src, len);
}
///
/// Copies a block of memory from one location to another.
///
/// A pointer to the starting address of the copied block's destination.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
///
/// CopyMemory runs faster than .
/// However, if both blocks overlap the result is undefined.
///
public static unsafe void CopyMemory(IntPtr dest, IntPtr src, long len)
{
CopyMemory((byte*)dest, (byte*)src, checked((int)len));
}
///
/// Copies a block of memory into an array.
///
/// An array used as the destination of the copy process.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
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();
}
}
///
/// Copies a block of memory into an array.
///
/// An array used as the destination of the copy process.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(Array dest, void* src, long len)
{
CopyMemory(dest, (byte*)src, checked((int)len));
}
///
/// Copies a block of memory into an array.
///
/// An array used as the destination of the copy process.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(Array dest, IntPtr src, int len)
{
CopyMemory(dest, (byte*)src, len);
}
///
/// Copies a block of memory into an array.
///
/// An array used as the destination of the copy process.
/// A pointer to the starting address of the block of memory to copy.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(Array dest, IntPtr src, long len)
{
CopyMemory(dest, (byte*)src, checked((int)len));
}
///
/// Copies the content of an array to a memory location.
///
/// A pointer to the starting address of the copied block's destination.
/// An array used as the source of the copy process.
/// The size of the block of memory to copy, in bytes.
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();
}
}
///
/// Copies the content of an array to a memory location.
///
/// A pointer to the starting address of the copied block's destination.
/// An array used as the source of the copy process.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(void* dest, Array src, long len)
{
CopyMemory((byte*)dest, src, checked((int)len));
}
///
/// Copies the content of an array to a memory location.
///
/// A pointer to the starting address of the copied block's destination.
/// An array used as the source of the copy process.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(IntPtr dest, Array src, int len)
{
CopyMemory((byte*)dest, src, len);
}
///
/// Copies the content of an array to a memory location.
///
/// A pointer to the starting address of the copied block's destination.
/// An array used as the source of the copy process.
/// The size of the block of memory to copy, in bytes.
public static unsafe void CopyMemory(IntPtr dest, Array src, long len)
{
CopyMemory((byte*)dest, src, checked((int)len));
}
///
/// Copies the content of one array into another array.
///
/// An array used as the destination of the copy process.
/// An array used as the source of the copy process.
/// The size of the content to copy, in bytes.
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();
}
}
///
/// Copies the content of one array into another array.
///
/// An array used as the destination of the copy process.
/// An array used as the source of the copy process.
/// The size of the content to copy, in bytes.
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(ref T[] array, int length)
{
if ((array != null) && (length >= 0) && (array.Length != length))
{
Array.Resize(ref array, length);
}
}
internal static void Resize(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(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
///
/// 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.
///
/// Handle to the window whose DC is to be retrieved.
/// If this value is IntPtr.Zero, GetDC retrieves the DC for the entire screen.
/// 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.
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
///
/// 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.
///
/// Handle to the window whose DC is to be released.
/// Handle to the DC to be released.
/// Returns true on success, false on failure.
[DllImport("user32.dll")]
private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
///
/// 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.
///
/// Handle to a device context.
/// Pointer to a BITMAPINFO structure that specifies various attributes of the DIB,
/// including the bitmap dimensions and colors.
/// 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).
/// Pointer to a variable that receives a pointer to the location of the DIB bit values.
/// Handle to a file-mapping object that the function will use to create the DIB.
/// This parameter can be NULL.
/// 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.
/// 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.
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBSection(
IntPtr hdc,
[In] IntPtr pbmi,
uint iUsage,
out IntPtr ppvBits,
IntPtr hSection,
uint dwOffset);
///
/// 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.
///
/// Handle to a logical pen, brush, font, bitmap, region, or palette.
/// Returns true on success, false on failure.
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
///
/// Creates a compatible bitmap (DDB) from a DIB and, optionally, sets the bitmap bits.
///
/// Handle to a device context.
/// Pointer to a bitmap information header structure.
/// Specifies how the system initializes the bitmap bits - (use 4).
/// Pointer to an array of bytes containing the initial bitmap data.
/// Pointer to a BITMAPINFO structure that describes the dimensions
/// and color format of the array pointed to by the lpbInit parameter.
/// Specifies whether the bmiColors member of the BITMAPINFO structure
/// was initialized - (use 0).
/// Handle to a DIB or null on failure.
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBitmap(
IntPtr hdc,
IntPtr lpbmih,
uint fdwInit,
IntPtr lpbInit,
IntPtr lpbmi,
uint fuUsage);
///
/// Retrieves information for the specified graphics object.
///
/// Handle to the graphics object of interest.
/// Specifies the number of bytes of information to
/// be written to the buffer.
/// Pointer to a buffer that receives the information
/// about the specified graphics object.
/// 0 on failure.
[DllImport("gdi32.dll")]
private static extern int GetObject(IntPtr hgdiobj, int cbBuffer, IntPtr lpvObject);
///
/// Retrieves the bits of the specified compatible bitmap and copies them into a buffer
/// as a DIB using the specified format.
///
/// Handle to the device context.
/// Handle to the bitmap. This must be a compatible bitmap (DDB).
/// Specifies the first scan line to retrieve.
/// Specifies the number of scan lines to retrieve.
/// Pointer to a buffer to receive the bitmap data.
/// Pointer to a BITMAPINFO structure that specifies the desired
/// format for the DIB data.
/// Specifies the format of the bmiColors member of the
/// BITMAPINFO structure - (use 0).
/// 0 on failure.
[DllImport("gdi32.dll")]
private static extern unsafe int GetDIBits(
IntPtr hdc,
IntPtr hbmp,
uint uStartScan,
uint cScanLines,
IntPtr lpvBits,
IntPtr lpbmi,
uint uUsage);
///
/// Moves a block of memory from one location to another.
///
/// Pointer to the starting address of the move destination.
/// Pointer to the starting address of the block of memory to be moved.
/// Size of the block of memory to move, in bytes.
[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static unsafe extern void MoveMemory(void* dst, void* src, uint size);
///
/// The RtlCompareMemory routine compares blocks of memory
/// and returns the number of bytes that are equivalent.
///
/// A pointer to a block of memory to compare.
/// A pointer to a block of memory to compare.
/// Specifies the number of bytes to be compared.
/// RtlCompareMemory returns the number of bytes that compare as equal.
/// If all bytes compare as equal, the input Length is returned.
[DllImport("ntdll.dll", EntryPoint = "RtlCompareMemory", SetLastError = false)]
internal static unsafe extern uint RtlCompareMemory(void* buf1, void* buf2, uint count);
#endregion
}
}