WriteableBitmap 转 PNG
WriteableBitmap to PNG
我正在编写一个简单的 WindowsStore 应用程序,但我不知道如何将 WriteableBitmap
保存到 PNG 图像格式的某些内存流中以获取此 PNG 图像的字节。
到目前为止我能找到的是如何在 WP7.1 上执行此操作,但它不起作用。
任何人都可以分享片段或指向有用的资源吗?
更新:
我用WriteableBitmap
在上面画画
我有这个扩展方法。
public static async Task<byte[]> ConvertToPngBytes(this WriteableBitmap bitmap)
{
using (IRandomAccessStream memoryStream = new InMemoryRandomAccessStream())
{
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, memoryStream);
byte[] buf = bitmap.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buf);
await encode.FlushAsync();
await memoryStream.FlushAsync();
var stream = memoryStream.AsStream();
byte[] result = new byte[stream.Length];
stream.Read(result, 0, result.Length);
return result;
}
}
它挂在 await encode.FlushAsync();
我做了类似的事情
StorageFile photoFile = await StorageFile.GetFileFromPathAsync(Windows.ApplicationModel.Package.Current.InstalledLocation.Path + @"\Images\CurrentFace.jpg");
using (IRandomAccessStream fileStream = await photoFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, fileStream); //Here try PNG
byte[] buf = displaySource.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)displaySource.PixelWidth
, (uint)displaySource.PixelHeight, 96.0, 96.0, buf);
await encode.FlushAsync();
await fileStream.FlushAsync();
}
我没有使用过可写位图,所以我的回答不完整,但是从文件而不是从可写位图加载流要容易得多。我曾经做过 writablebitmap.pixelbuffer.asstream() 之类的事情,但这不起作用,因为流会丢失不在像素缓冲区
中的关键信息
这也是我保存到文件的代码。注意:必须有一个已经存在的文件可以保存到,所以你可以把一个空白的 .png 放在一个目录中,然后将你的真实图像保存到它。您可以将 writableBitmap 存储在 Framework 元素中,然后调用此函数。
async Task<RenderTargetBitmap> SaveToFileAsync(FrameworkElement uielement, StorageFile file)
{
if (file != null)
{
CachedFileManager.DeferUpdates(file);
Guid encoderId = GetBitmapEncoder(file.FileType);
try
{
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
return await CaptureToStreamAsync(uielement, stream, encoderId);
}
}
catch (Exception ex)
{
//DisplayMessage(ex.Message);
}
var status = await CachedFileManager.CompleteUpdatesAsync(file);
}
return null;
}
async Task<RenderTargetBitmap> CaptureToStreamAsync(FrameworkElement uielement, IRandomAccessStream stream, Guid encoderId)
{
try
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(uielement);
var pixels = await renderTargetBitmap.GetPixelsAsync();
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var encoder = await BitmapEncoder.CreateAsync(encoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
logicalDpi,
logicalDpi,
pixels.ToArray());
await encoder.FlushAsync();
return renderTargetBitmap;
}
catch (Exception ex)
{
//DisplayMessage(ex.Message);
}
return null;
}
您更新的代码不起作用,因为必须将 BitmapEncoder 分配给包含图片数据的流。当您使用 await BitmapEncoder.CreateAsync() 时,您使用的是没有数据的 memoryStream(它刚刚被初始化)。
事实证明,BitmapEncoder
需要一个充满 png 数据的流。我在互联网上找到的每个示例代码都需要一个现有的 PNG 文件或使用选择器等创建一个。我只是想将我的 WriteableBitmap
保存到 PNG 格式的字节数组中。
作为解决方案,我制作了一个 1x1 像素的 PNG 文件并将其字节复制到一个字节数组。我可以用这个字节数组做一些操作,不需要 write/read 来自文件的任何东西。
解决方法如下:
static readonly byte[] PngBytes = {
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1,
8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 1, 115, 82, 71, 66, 0, 174, 206, 28, 233, 0,
0, 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, 0, 9, 112, 72, 89, 115,
0, 0, 14, 195, 0, 0, 14, 195, 1, 199, 111, 168, 100, 0, 0, 0, 24, 116, 69, 88, 116, 83,
111, 102, 116, 119, 97, 114, 101, 0, 112, 97, 105, 110, 116, 46, 110, 101, 116, 32, 52,
46, 48, 46, 51, 140, 230, 151, 80, 0, 0, 0, 13, 73, 68, 65, 84, 24, 87, 99, 248, 255,
255, 255, 127, 0, 9, 251, 3, 253, 5, 67, 69, 202, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66,
96, 130
};
public static async Task<byte[]> ConvertToPngBytes(this WriteableBitmap bitmap)
{
using (var memoryStream = new InMemoryRandomAccessStream())
{
await memoryStream.WriteAsync(PngBytes.AsBuffer());
memoryStream.Seek(0);
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,
memoryStream);
byte[] buffer = bitmap.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
(uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buffer);
await encode.FlushAsync();
var stream = memoryStream.AsStream();
stream.Seek(0, SeekOrigin.Begin);
byte[] result = new byte[stream.Length];
stream.Read(result, 0, result.Length);
return result;
}
}
我正在编写一个简单的 WindowsStore 应用程序,但我不知道如何将 WriteableBitmap
保存到 PNG 图像格式的某些内存流中以获取此 PNG 图像的字节。
到目前为止我能找到的是如何在 WP7.1 上执行此操作,但它不起作用。
任何人都可以分享片段或指向有用的资源吗?
更新:
我用WriteableBitmap
在上面画画
我有这个扩展方法。
public static async Task<byte[]> ConvertToPngBytes(this WriteableBitmap bitmap)
{
using (IRandomAccessStream memoryStream = new InMemoryRandomAccessStream())
{
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, memoryStream);
byte[] buf = bitmap.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buf);
await encode.FlushAsync();
await memoryStream.FlushAsync();
var stream = memoryStream.AsStream();
byte[] result = new byte[stream.Length];
stream.Read(result, 0, result.Length);
return result;
}
}
它挂在 await encode.FlushAsync();
我做了类似的事情
StorageFile photoFile = await StorageFile.GetFileFromPathAsync(Windows.ApplicationModel.Package.Current.InstalledLocation.Path + @"\Images\CurrentFace.jpg");
using (IRandomAccessStream fileStream = await photoFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, fileStream); //Here try PNG
byte[] buf = displaySource.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)displaySource.PixelWidth
, (uint)displaySource.PixelHeight, 96.0, 96.0, buf);
await encode.FlushAsync();
await fileStream.FlushAsync();
}
我没有使用过可写位图,所以我的回答不完整,但是从文件而不是从可写位图加载流要容易得多。我曾经做过 writablebitmap.pixelbuffer.asstream() 之类的事情,但这不起作用,因为流会丢失不在像素缓冲区
中的关键信息这也是我保存到文件的代码。注意:必须有一个已经存在的文件可以保存到,所以你可以把一个空白的 .png 放在一个目录中,然后将你的真实图像保存到它。您可以将 writableBitmap 存储在 Framework 元素中,然后调用此函数。
async Task<RenderTargetBitmap> SaveToFileAsync(FrameworkElement uielement, StorageFile file)
{
if (file != null)
{
CachedFileManager.DeferUpdates(file);
Guid encoderId = GetBitmapEncoder(file.FileType);
try
{
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
return await CaptureToStreamAsync(uielement, stream, encoderId);
}
}
catch (Exception ex)
{
//DisplayMessage(ex.Message);
}
var status = await CachedFileManager.CompleteUpdatesAsync(file);
}
return null;
}
async Task<RenderTargetBitmap> CaptureToStreamAsync(FrameworkElement uielement, IRandomAccessStream stream, Guid encoderId)
{
try
{
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(uielement);
var pixels = await renderTargetBitmap.GetPixelsAsync();
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
var encoder = await BitmapEncoder.CreateAsync(encoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
logicalDpi,
logicalDpi,
pixels.ToArray());
await encoder.FlushAsync();
return renderTargetBitmap;
}
catch (Exception ex)
{
//DisplayMessage(ex.Message);
}
return null;
}
您更新的代码不起作用,因为必须将 BitmapEncoder 分配给包含图片数据的流。当您使用 await BitmapEncoder.CreateAsync() 时,您使用的是没有数据的 memoryStream(它刚刚被初始化)。
事实证明,BitmapEncoder
需要一个充满 png 数据的流。我在互联网上找到的每个示例代码都需要一个现有的 PNG 文件或使用选择器等创建一个。我只是想将我的 WriteableBitmap
保存到 PNG 格式的字节数组中。
作为解决方案,我制作了一个 1x1 像素的 PNG 文件并将其字节复制到一个字节数组。我可以用这个字节数组做一些操作,不需要 write/read 来自文件的任何东西。
解决方法如下:
static readonly byte[] PngBytes = {
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1,
8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 1, 115, 82, 71, 66, 0, 174, 206, 28, 233, 0,
0, 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, 0, 9, 112, 72, 89, 115,
0, 0, 14, 195, 0, 0, 14, 195, 1, 199, 111, 168, 100, 0, 0, 0, 24, 116, 69, 88, 116, 83,
111, 102, 116, 119, 97, 114, 101, 0, 112, 97, 105, 110, 116, 46, 110, 101, 116, 32, 52,
46, 48, 46, 51, 140, 230, 151, 80, 0, 0, 0, 13, 73, 68, 65, 84, 24, 87, 99, 248, 255,
255, 255, 127, 0, 9, 251, 3, 253, 5, 67, 69, 202, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66,
96, 130
};
public static async Task<byte[]> ConvertToPngBytes(this WriteableBitmap bitmap)
{
using (var memoryStream = new InMemoryRandomAccessStream())
{
await memoryStream.WriteAsync(PngBytes.AsBuffer());
memoryStream.Seek(0);
BitmapEncoder encode = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,
memoryStream);
byte[] buffer = bitmap.PixelBuffer.ToArray();
encode.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
(uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buffer);
await encode.FlushAsync();
var stream = memoryStream.AsStream();
stream.Seek(0, SeekOrigin.Begin);
byte[] result = new byte[stream.Length];
stream.Read(result, 0, result.Length);
return result;
}
}