所以这是我经过大量谷歌搜索和试错编码后得到的解决方案:
这里的目标是找出如何在 WinRT 中操作图像,特别是在后台任务中。后台任务比普通的 WinRT 项目更受限制,因为它们必须是Windows 运行时组件类型。NuGet 上针对 WinRT 的 99% 可用库仅针对默认 WinRT 项目,因此它们不能在 Windows 运行时组件项目中使用。
起初我尝试使用著名的 WriteableBitmapEx 库——将必要的代码移植到我的 winmd 项目中。WBE 项目甚至还有针对 winmd 的分支,但尚未完成。我在将 [ReadOnlyArray]、[WriteOnlyArray] 属性添加到数组类型的方法参数以及将项目命名空间更改为不以“Windows”开头的东西之后编译它 - winmd 项目限制。
即使我能够在我的后台任务项目中使用此库,它也无法正常工作,因为正如我发现的那样,WriteableBitmap 必须在 UI 线程中实例化,而据我在后台任务中所知,这是不可能的。
与此同时,我还发现了这篇关于 WinRT 中的图像处理的 MSDN 文章。大多数示例仅在 JavaScript 部分中,因此我必须先将其转换为 C#。我还在StackOverflow 上找到了这篇关于 WinRT 中的图像处理的有用文章。
internal static async Task LoadTileImageInternalAsync(string imagePath)
{
string tileName = imagePath.GetHashedTileName();
StorageFile origFile = await ApplicationData.Current.LocalFolder.GetFileAsync(imagePath);
// open file for the new tile image file
StorageFile tileFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(tileName, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream tileStream = await tileFile.OpenAsync(FileAccessMode.ReadWrite))
{
// get width and height from the original image
IRandomAccessStreamWithContentType stream = await origFile.OpenReadAsync();
ImageProperties properties = await origFile.Properties.GetImagePropertiesAsync();
uint width = properties.Width;
uint height = properties.Height;
// get proper decoder for the input file - jpg/png/gif
BitmapDecoder decoder = await GetProperDecoder(stream, imagePath);
if (decoder == null) return; // should not happen
// get byte array of actual decoded image
PixelDataProvider data = await decoder.GetPixelDataAsync();
byte[] bytes = data.DetachPixelData();
// create encoder for saving the tile image
BitmapPropertySet propertySet = new BitmapPropertySet();
// create class representing target jpeg quality - a bit obscure, but it works
BitmapTypedValue qualityValue = new BitmapTypedValue(TargetJpegQuality, PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
// create the target jpeg decoder
BitmapEncoder be = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, tileStream, propertySet);
be.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96.0, 96.0, bytes);
// crop the image, if it's too big
if (width > MaxImageWidth || height > MaxImageHeight)
{
BitmapBounds bounds = new BitmapBounds();
if (width > MaxImageWidth)
{
bounds.Width = MaxImageWidth;
bounds.X = (width - MaxImageWidth) / 2;
}
else bounds.Width = width;
if (height > MaxImageHeight)
{
bounds.Height = MaxImageHeight;
bounds.Y = (height - MaxImageHeight) / 2;
}
else bounds.Height = height;
be.BitmapTransform.Bounds = bounds;
}
// save the target jpg to the file
await be.FlushAsync();
}
}
private static async Task<BitmapDecoder> GetProperDecoder(IRandomAccessStreamWithContentType stream, string imagePath)
{
string ext = Path.GetExtension(imagePath);
switch (ext)
{
case ".jpg":
case ".jpeg":
return await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, stream);
case ".png":
return await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, stream);
case ".gif":
return await BitmapDecoder.CreateAsync(BitmapDecoder.GifDecoderId, stream);
}
return null;
}
在此示例中,我们打开一个文件,将其解码为字节数组,然后将其编码回具有不同大小/格式/质量的新文件。
结果是即使在 Windows 运行时组件类且没有 WriteableBitmapEx 库的情况下,图像操作也能完全正常工作。