1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
|
#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
{
/// <summary>
/// Collection of interchange extension methods for the WriteableBitmap class.
/// </summary>
internal
#if WPF
unsafe
#endif
static partial class WriteableBitmapExtensions
{
#region Methods
#region Byte Array
/// <summary>
/// Copies the Pixels from the WriteableBitmap into a ARGB byte array starting at a specific Pixels index.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="offset">The starting Pixels index.</param>
/// <param name="count">The number of Pixels to copy, -1 for all</param>
/// <returns>The color buffer as byte ARGB values.</returns>
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;
}
}
/// <summary>
/// Copies the Pixels from the WriteableBitmap into a ARGB byte array.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="count">The number of pixels to copy.</param>
/// <returns>The color buffer as byte ARGB values.</returns>
internal static byte[] ToByteArray(this WriteableBitmap bmp, int count)
{
return bmp.ToByteArray(0, count);
}
/// <summary>
/// Copies all the Pixels from the WriteableBitmap into a ARGB byte array.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <returns>The color buffer as byte ARGB values.</returns>
internal static byte[] ToByteArray(this WriteableBitmap bmp)
{
return bmp.ToByteArray(0, -1);
}
/// <summary>
/// Copies color information from an ARGB byte array into this WriteableBitmap starting at a specific buffer index.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="offset">The starting index in the buffer.</param>
/// <param name="count">The number of bytes to copy from the buffer.</param>
/// <param name="buffer">The color buffer as byte ARGB values.</param>
/// <returns>The WriteableBitmap that was passed as parameter.</returns>
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;
}
}
/// <summary>
/// Copies color information from an ARGB byte array into this WriteableBitmap.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="count">The number of bytes to copy from the buffer.</param>
/// <param name="buffer">The color buffer as byte ARGB values.</param>
/// <returns>The WriteableBitmap that was passed as parameter.</returns>
internal static WriteableBitmap FromByteArray(this WriteableBitmap bmp, byte[] buffer, int count)
{
return bmp.FromByteArray(buffer, 0, count);
}
/// <summary>
/// Copies all the color information from an ARGB byte array into this WriteableBitmap.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="buffer">The color buffer as byte ARGB values.</param>
/// <returns>The WriteableBitmap that was passed as parameter.</returns>
internal static WriteableBitmap FromByteArray(this WriteableBitmap bmp, byte[] buffer)
{
return bmp.FromByteArray(buffer, 0, buffer.Length);
}
#endregion
#region TGA File
/// <summary>
/// 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
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="destination">The destination stream.</param>
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
/// <summary>
/// Loads an image from the applications resource file and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="relativePath">Only the relative path to the resource file. The assembly name is retrieved automatically.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[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
/// <summary>
/// Loads an image from the applications content and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="uri">The URI to the content file.</param>
/// <param name="pixelFormat">The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[Obsolete("Please use BitmapContext.FromContent instead of this FromContent method.")]
internal static Task<WriteableBitmap> FromContent(this WriteableBitmap bmp, Uri uri, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromContent(uri, pixelFormat);
}
/// <summary>
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="stream">The stream with the image data.</param>
/// <param name="pixelFormat">The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[Obsolete("Please use BitmapContext.FromStream instead of this FromStream method.")]
internal static Task<WriteableBitmap> FromStream(this WriteableBitmap bmp, Stream stream, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromStream(stream, pixelFormat);
}
/// <summary>
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="stream">The stream with the image data.</param>
/// <param name="pixelFormat">The pixel format of the stream data. If Unknown is provided as param, the default format of the BitmapDecoder is used.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[Obsolete("Please use BitmapContext.FromStream instead of this FromStream method.")]
internal static Task<WriteableBitmap> FromStream(this WriteableBitmap bmp, IRandomAccessStream stream, BitmapPixelFormat pixelFormat = BitmapPixelFormat.Unknown)
{
return BitmapFactory.FromStream(stream, pixelFormat);
}
/// <summary>
/// Encodes the data from a WriteableBitmap into a stream.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="destinationStream">The stream which will take the image data.</param>
/// <param name="encoderId">The encoder GUID to use like BitmapEncoder.JpegEncoderId etc.</param>
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();
}
/// <summary>
/// Encodes the data from a WriteableBitmap as JPEG into a stream.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="destinationStream">The stream which will take the JPEG image data.</param>
internal static async Task ToStreamAsJpeg(this WriteableBitmap bmp, IRandomAccessStream destinationStream)
{
await ToStream(bmp, destinationStream, BitmapEncoder.JpegEncoderId);
}
/// <summary>
/// Loads the data from a pixel buffer like the RenderTargetBitmap provides and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="pixelBuffer">The source pixel buffer with the image data.</param>
/// <param name="width">The width of the image data.</param>
/// <param name="height">The height of the image data.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[Obsolete("Please use BitmapContext.FromPixelBuffer instead of this FromPixelBuffer method.")]
internal static Task<WriteableBitmap> FromPixelBuffer(this WriteableBitmap bmp, IBuffer pixelBuffer, int width, int height)
{
return BitmapFactory.FromPixelBuffer(pixelBuffer, width, height);
}
#else
/// <summary>
/// Loads an image from the applications content and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="relativePath">Only the relative path to the content file.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[Obsolete("Please use BitmapContext.FromContent instead of this FromContent method.")]
internal static WriteableBitmap FromContent(this WriteableBitmap bmp, string relativePath)
{
return BitmapFactory.FromContent(relativePath);
}
/// <summary>
/// Loads the data from an image stream and returns a new WriteableBitmap. The passed WriteableBitmap is not used.
/// </summary>
/// <param name="bmp">The WriteableBitmap.</param>
/// <param name="stream">The stream with the image data.</param>
/// <returns>A new WriteableBitmap containing the pixel data.</returns>
[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
}
}
|