#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 } }