#region Copyright information
// <copyright file="BitmapSourceTypeConverter.cs">
// Licensed under Microsoft Public License (Ms-PL)
// http://wpflocalizeextension.codeplex.com/license
// </copyright>
// <author>Bernhard Millauer</author>
// <author>Uwe Mayer</author>
#endregion

namespace WPFLocalizeExtension.TypeConverters
{
#region Uses
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
#endregion

/// <summary>
/// A type converter class for Bitmap resources that are used in WPF.
/// </summary>
public class BitmapSourceTypeConverter : TypeConverter
{
/// <summary>
/// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context.
/// </summary>
/// <param name="context">An <see cref="ITypeDescriptorContext"/> that provides a format context.</param>
/// <param name="sourceType">A <see cref="Type"/> that represents the type you want to convert from.</param>
/// <returns>true if this converter can perform the conversion; otherwise, false.</returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return ((sourceType != null) && (sourceType.Equals(typeof(System.Drawing.Bitmap))));
}

/// <summary>
/// Returns whether this converter can convert the object to the specified type, using the specified context.
/// </summary>
/// <param name="context">An <see cref="ITypeDescriptorContext"/> that provides a format context.</param>
/// <param name="destinationType">A <see cref="Type"/> that represents the type you want to convert to.</param>
/// <returns>true if this converter can perform the conversion; otherwise, false.</returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ((destinationType != null) && (destinationType.Equals(typeof(System.Drawing.Bitmap))));
}

/// <summary>
/// Converts the given object to the type of this converter, using the specified context and culture information.
/// </summary>
/// <param name="context">An <see cref="ITypeDescriptorContext"/> that provides a format context.</param>
/// <param name="culture">The <see cref="CultureInfo"/> to use as the current culture.</param>
/// <param name="value">The <see cref="Object"/> to convert.</param>
/// <returns>An <see cref="Object"/> that represents the converted value.</returns>
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
Bitmap bitmap = value as Bitmap;

if (bitmap == null)
return null;

IntPtr bmpPt = bitmap.GetHbitmap();

// create the bitmapSource
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmpPt,
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

// freeze the bitmap to avoid hooking events to the bitmap
bitmapSource.Freeze();

// free memory
DeleteObject(bmpPt);

// return bitmapSource
return bitmapSource;
}

/// <summary>
/// Frees memory of a pointer.
/// </summary>
/// <param name="o">Object to remove from memory.</param>
/// <returns>0 if the removing was success, otherwise another number.</returns>
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern int DeleteObject(IntPtr o);

/// <summary>
/// Converts the given value object to the specified type, using the specified context and culture information.
/// </summary>
/// <param name="context">An <see cref="ITypeDescriptorContext"/> that provides a format context.</param>
/// <param name="culture">The <see cref="CultureInfo"/> to use as the current culture.</param>
/// <param name="value">The <see cref="Object"/> to convert.</param>
/// <param name="destinationType">The <see cref="Type"/> to convert the value parameter to.</param>
/// <returns>An <see cref="Object"/> that represents the converted value.</returns>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
BitmapSource source = value as BitmapSource;

if (value == null)
return null;

Bitmap bmp = new Bitmap(
source.PixelWidth,
source.PixelHeight,
PixelFormat.Format32bppPArgb);

BitmapData data = bmp.LockBits(
new Rectangle(System.Drawing.Point.Empty, bmp.Size),
ImageLockMode.WriteOnly,
PixelFormat.Format32bppPArgb);

source.CopyPixels(
Int32Rect.Empty,
data.Scan0,
data.Height * data.Stride,
data.Stride);

bmp.UnlockBits(data);

return bmp;
}
}
}