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