#region Header
//
// Project: WriteableBitmapEx - WriteableBitmap extensions
// Description: Collection of interchange extension methods for the WriteableBitmap class.
//
// Changed by: $Author: unknown $
// Changed on: $Date: 2015-03-17 16:18:14 +0100 (Di, 17 Mrz 2015) $
// Changed in: $Revision: 113386 $
// Project: $URL: https://writeablebitmapex.svn.codeplex.com/svn/trunk/Source/WriteableBitmapEx/WriteableBitmapConvertExtensions.cs $
// Id: $Id: WriteableBitmapConvertExtensions.cs 113386 2015-03-17 15:18:14Z unknown $
//
//
// Copyright © 2009-2015 Rene Schulte and WriteableBitmapEx Contributors
//
// This code is open source. Please read the License.txt for details. No worries, we won't sue you! ;)
//
#endregion
using System;
using System.IO;
using System.Reflection;
#if NETFX_CORE
using Windows.ApplicationModel.Resources;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using Windows.Graphics.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;
namespace Windows.UI.Xaml.Media.Imaging
#else
namespace System.Windows.Media.Imaging
#endif
{
///
/// Collection of interchange extension methods for the WriteableBitmap class.
///
internal
#if WPF
unsafe
#endif
static partial class WriteableBitmapExtensions
{
#region Methods
#region Byte Array
///
/// Copies the Pixels from the WriteableBitmap into a ARGB byte array starting at a specific Pixels index.
///
/// The WriteableBitmap.
/// The starting Pixels index.
/// The number of Pixels to copy, -1 for all
/// The color buffer as byte ARGB values.
internal static byte[] ToByteArray(this WriteableBitmap bmp, int offset, int count)
{
using (var context = bmp.GetBitmapContext())
{
if (count == -1)
{
// Copy all to byte array
count = context.Length;
}
var len = count * SizeOfArgb;
var result = new byte[len]; // ARGB
BitmapContext.BlockCopy(context, offset, result, 0, len);
return result;
}
}
///
/// Copies the Pixels from the WriteableBitmap into a ARGB byte array.
///
/// The WriteableBitmap.
/// The number of pixels to copy.
/// The color buffer as byte ARGB values.
internal static byte[] ToByteArray(this WriteableBitmap bmp, int count)
{
return bmp.ToByteArray(0, count);
}
///
/// Copies all the Pixels from the WriteableBitmap into a ARGB byte array.
///
/// The WriteableBitmap.
/// The color buffer as byte ARGB values.
internal static byte[] ToByteArray(this WriteableBitmap bmp)
{
return bmp.ToByteArray(0, -1);
}
///
/// Copies color information from an ARGB byte array into this WriteableBitmap starting at a specific buffer index.
///
/// The WriteableBitmap.
/// The starting index in the buffer.
/// The number of bytes to copy from the buffer.
/// The color buffer as byte ARGB values.
/// The WriteableBitmap that was passed as parameter.
internal static WriteableBitmap FromByteArray(this WriteableBitmap bmp, byte[] buffer, int offset, int count)
{
using (var context = bmp.GetBitmapContext())
{
BitmapContext.BlockCopy(buffer, offset, context, 0, count);
return bmp;
}
}
///
/// Copies color information from an ARGB byte array into this WriteableBitmap.
///
/// The WriteableBitmap.
/// The number of bytes to copy from the buffer.
/// The color buffer as byte ARGB values.
/// The WriteableBitmap that was passed as parameter.
internal static WriteableBitmap FromByteArray(this WriteableBitmap bmp, byte[] buffer, int count)
{
return bmp.FromByteArray(buffer, 0, count);
}
///
/// Copies all the color information from an ARGB byte array into this WriteableBitmap.
///
/// The WriteableBitmap.
/// The color buffer as byte ARGB values.
/// The WriteableBitmap that was passed as parameter.
internal static WriteableBitmap FromByteArray(this WriteableBitmap bmp, byte[] buffer)
{
return bmp.FromByteArray(buffer, 0, buffer.Length);
}
#endregion
#region TGA File
///
/// Writes the WriteableBitmap as a TGA image to a stream.
/// Used with permission from Nokola: http://nokola.com/blog/post/2010/01/21/Quick-and-Dirty-Output-of-WriteableBitmap-as-TGA-Image.aspx
///
/// The WriteableBitmap.
/// The destination stream.
internal static void WriteTga(this WriteableBitmap bmp, Stream destination)
{
using (var context = bmp.GetBitmapContext())
{
int width = context.Width;
int height = context.Height;
var pixels = context.Pixels;
byte[] data = new byte[context.Length * SizeOfArgb];
// Copy bitmap data as BGRA
int offsetSource = 0;
int width4 = width << 2;
int width8 = width << 3;
int offsetDest = (height - 1) * width4;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Account for pre-multiplied alpha
int c = pixels[offsetSource];
var a = (byte)(c >> 24);
// Prevent division by zero
int ai = a;
if (ai == 0)
{
ai = 1;
}
// Scale inverse alpha to use cheap integer mul bit shift
ai = ((255 << 8) / ai);
data[offsetDest + 3] = (byte)a; // A
data[offsetDest + 2] = (byte)((((c >> 16) & 0xFF) * ai) >> 8); // R
data[offsetDest + 1] = (byte)((((c >> 8) & 0xFF) * ai) >> 8); // G
data[offsetDest] = (byte)((((c & 0xFF) * ai) >> 8)); // B
offsetSource++;
offsetDest += SizeOfArgb;
}
offsetDest -= width8;
}
// Create header
var header = new byte[]
{
0, // ID length
0, // no color map
2, // uncompressed, true color
0, 0, 0, 0,
0,
0, 0, 0, 0, // x and y origin
(byte)(width & 0x00FF),
(byte)((width & 0xFF00) >> 8),
(byte)(height & 0x00FF),
(byte)((height & 0xFF00) >> 8),
32, // 32 bit bitmap
0
};
// Write header and data
using (var writer = new BinaryWriter(destination))
{
writer.Write(header);
writer.Write(data);
}
}
}
#endregion
#region Resource
#if !NETFX_CORE
///
/// Loads an image from the applications resource file and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// Only the relative path to the resource file. The assembly name is retrieved automatically.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromResource instead of this FromResource method.")]
internal static WriteableBitmap FromResource(this WriteableBitmap bmp, string relativePath)
{
return BitmapFactory.FromResource(relativePath);
}
#endif
#if NETFX_CORE
///
/// Loads an image from the applications content and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// The URI to the content file.
/// The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromContent instead of this FromContent method.")]
internal static Task FromContent(this WriteableBitmap bmp, Uri uri, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromContent(uri, pixelFormat);
}
///
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// The stream with the image data.
/// The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromStream instead of this FromStream method.")]
internal static Task FromStream(this WriteableBitmap bmp, Stream stream, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromStream(stream, pixelFormat);
}
///
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// The stream with the image data.
/// The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromStream instead of this FromStream method.")]
internal static Task FromStream(this WriteableBitmap bmp, IRandomAccessStream stream, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromStream(stream, pixelFormat);
}
///
/// Encodes the data from a WriteableBitmap into a stream.
///
/// The WriteableBitmap.
/// The stream which will take the image data.
/// The encoder GUID to use like BitmapEncoder.JpegEncoderId etc.
internal static async Task ToStream(this WriteableBitmap bmp, IRandomAccessStream destinationStream, Guid encoderId)
{
// Copy buffer to pixels
byte[] pixels;
using (var stream = bmp.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
// Encode pixels into stream
var encoder = await BitmapEncoder.CreateAsync(encoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)bmp.PixelWidth, (uint)bmp.PixelHeight, 96, 96, pixels);
await encoder.FlushAsync();
}
///
/// Encodes the data from a WriteableBitmap as JPEG into a stream.
///
/// The WriteableBitmap.
/// The stream which will take the JPEG image data.
internal static async Task ToStreamAsJpeg(this WriteableBitmap bmp, IRandomAccessStream destinationStream)
{
await ToStream(bmp, destinationStream, BitmapEncoder.JpegEncoderId);
}
///
/// Loads the data from a pixel buffer like the RenderTargetBitmap provides and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// The source pixel buffer with the image data.
/// The width of the image data.
/// The height of the image data.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromPixelBuffer instead of this FromPixelBuffer method.")]
internal static Task FromPixelBuffer(this WriteableBitmap bmp, IBuffer pixelBuffer, int width, int height)
{
return BitmapFactory.FromPixelBuffer(pixelBuffer, width, height);
}
#else
///
/// Loads an image from the applications content and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// Only the relative path to the content file.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromContent instead of this FromContent method.")]
internal static WriteableBitmap FromContent(this WriteableBitmap bmp, string relativePath)
{
return BitmapFactory.FromContent(relativePath);
}
///
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
///
/// The WriteableBitmap.
/// The stream with the image data.
/// A new WriteableBitmap containing the pixel data.
[Obsolete("Please use BitmapContext.FromStream instead of this FromStream method.")]
internal static WriteableBitmap FromStream(this WriteableBitmap bmp, Stream stream)
{
return BitmapFactory.FromStream(stream);
}
#endif
#endregion
#endregion
}
}