我有简单的问题,但到目前为止,我发现没有答案:如何调整JPEG图像在C#的WinRT / WinMD项目并将其保存为新的JPEG?
我在开发Windows 8 Metro应用下载日常的图像格式的某些网站和一个Live平铺显示它。 问题是图像必须小于1024×1024而小于200kB的小,否则它不会显示在瓷砖上: http://msdn.microsoft.com/en-us/library/windows/apps/hh465403.aspx
如果我得到了较大的图像,如何调整它的动态磁贴是贴合? 我想只是简单的调整大小一样宽/ 2和高度/ 2与保持纵横比。
这里的具体要求是,代码必须为Windows运行时组件运行,因此WriteableBitmapEx库将在这里工作 - 这是仅适用于普通的WinRT项目。 甚至还有WriteableBitmapEx作为winmd项目的一个分支,但它准备远远。
如何扩展和取自农作物例子在这里 :
async private void BitmapTransformTest()
{
// hard coded image location
string filePath = "C:\\Users\\Public\\Pictures\\Sample Pictures\\fantasy-dragons-wallpaper.jpg";
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(ras, decoder);
// convert the entire bitmap to a 100px by 100px bitmap
enc.BitmapTransform.ScaledHeight = 100;
enc.BitmapTransform.ScaledWidth = 100;
BitmapBounds bounds = new BitmapBounds();
bounds.Height = 50;
bounds.Width = 50;
bounds.X = 50;
bounds.Y = 50;
enc.BitmapTransform.Bounds = bounds;
// write out to the stream
try
{
await enc.FlushAsync();
}
catch (Exception ex)
{
string s = ex.ToString();
}
// render the stream to the screen
BitmapImage bImg = new BitmapImage();
bImg.SetSource(ras);
img.Source = bImg; // image element in xaml
}
更简单的代码来重新大小的图像,没有收成。 在下面的代码重新大小的图像作为80×80
using (var sourceStream = await sourceFile.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceStream);
BitmapTransform transform = new BitmapTransform() { ScaledHeight = 80, ScaledWidth = 80 };
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
using (var destinationStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, 80, 80, 96, 96, pixelData.DetachPixelData());
await encoder.FlushAsync();
}
}
资源
因此,这里是我的解决方案我来了很多谷歌搜索和试验/错误编码后:
这里的目标是要找出如何处理图像在WinRT中,特别是在后台任务 。 后台任务甚至比只是普通的WinRT项目比较有限,因为它们的类型必须为Windows运行时组件 。 上的NuGet针对WinRT的可用库的99%的目标只有默认的WinRT的项目,因此,他们无法在Windows运行时组件项目中使用。
起初,我尝试使用知名WriteableBitmapEx库 -移植必要的代码,以我的winmd项目。 甚至还有的WBE项目瞄准winmd的分支 ,但它是未完成的。 我做了添加[ReadOnlyArray]后,编译,[WriteOnlyArray]属性类型的数组方法的参数,也改变项目名称空间的东西后,不与“视窗”开始 - winmd项目的限制。
虽然我能够用我的后台任务的项目该库它不工作,因为,我发现,WriteableBitmap的必须在UI线程实例化,这是不可能的,因为据我所知,在后台任务。
同时,我也发现了这个关于WinRT的图像处理MSDN文章 。 大多数样品的,只有在JavaScript部分,所以只好先将其转换为C#。 我还发现这是很有帮助的有关WinRT的图像处理StackOverflow上的文章 。
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库。
下面是更短的版本,而无需访问像素数据的开销。
using (var sourceFileStream = await sourceFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
using (var destFileStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceFileStream);
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(destFileStream, decoder);
enc.BitmapTransform.ScaledWidth = newWidth;
enc.BitmapTransform.ScaledHeight = newHeight;
await enc.FlushAsync();
await destFileStream.FlushAsync();
}
我只花了半小时试图找出这一个,我有一个字节数组是一个JPG,并试图给出答案......我无法得到它的工作,所以我把一个新的答案...希望这会帮助别人了...我转换JPG至250/250像素
private async Task<BitmapImage> ByteArrayToBitmapImage(byte[] byteArray)
{
BitmapImage image = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes((byte[])byteArray);
writer.StoreAsync().GetResults();
}
image.SetSource(stream);
}
image.DecodePixelHeight = 250;
image.DecodePixelWidth = 250;
return image;
}
如果你要那么画质的图像BitmapTransform添加InterpolationMode = BitmapInterpolationMode.Fant,这里是例子
`公共静态异步任务ResizeImage(Windows.Storage.StorageFile imgeTOBytes,INT maxWidth,INT maxHeight){
using (var sourceStream = await imgeTOBytes.OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(sourceStream);
double widthRatio = (double)maxWidth / decoder.OrientedPixelWidth;
double heightRatio = (double)maxHeight / decoder.OrientedPixelHeight;
double scaleRatio = Math.Min(widthRatio, heightRatio);
uint aspectHeight = (uint)Math.Floor((double)decoder.OrientedPixelHeight * scaleRatio);
uint aspectWidth = (uint)Math.Floor((double)decoder.OrientedPixelWidth * scaleRatio);
BitmapTransform transform = new BitmapTransform() { InterpolationMode = BitmapInterpolationMode.Fant, ScaledHeight = aspectHeight, ScaledWidth = aspectWidth };
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Rgba8,
BitmapAlphaMode.Premultiplied,
transform,
ExifOrientationMode.RespectExifOrientation,
ColorManagementMode.DoNotColorManage);
using (var destinationStream = await imgeTOBytes.OpenAsync(FileAccessMode.ReadWrite))
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, destinationStream);
encoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, aspectWidth, aspectHeight, 96, 96, pixelData.DetachPixelData());
await encoder.FlushAsync();
}
}`