我正在编写一个Windows 8.1应用程序(WINPRT)。用户从图片库中挑选照片,这张图片必须上传到服务器上。因此,我需要将其转换为Base64字符串。
所以,对于Photo Base64字符串,我遵循的流是:args.Files > StorageFile >>像素流> base64string,但是图像可能非常大,所以我将其调整为48x48,并将其转换为像素,然后再转换为字符串。
应用程序崩溃或手机卡在Convert.ToBase64String(pixels);上
我做错了吗?我还在转换全维图像的像素吗?
public async void ConvertPictureToBase64()
{
string ImageIntoBase64String = "";
WriteableBitmap WriteableBitmapObject = new WriteableBitmap(1, 1);
var storageStream = await StorageFileObject.OpenAsync(FileAccessMode.Read);
IRandomAccessStream IRandomAccessStreamObject = await StorageFileObject.OpenReadAsync();
WriteableBitmapObject.SetSource(IRandomAccessStreamObject);
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, storageStream);
var pixelStream = WriteableBitmapObject.PixelBuffer.AsStream();
var pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)WriteableBitmapObject.PixelWidth, (uint)WriteableBitmapObject.PixelHeight, 48, 48, pixels);
ImageIntoBase64String = Convert.ToBase64String(pixels);
await encoder.FlushAsync();
}发布于 2015-02-21 15:08:50
您可以使用我的方法压缩图像,然后将其转换为Base64字符串。
注意:,我正在使用WriteableBitmapEx扩展类来调整图像的大小。另外,需要在UI线程上实例化WriteableBitmap类,因此如果您像我一样在后台任务上运行此方法,则必须将引用传递给您所在的页面,以便该方法能够在使用WriteableBitmap类时使当前的UI dispatcher工作。
下面是:
public static async Task<String> ToCompressedBase64(this StorageFile imageFile, Page localPage)
{
//Get the stream from the StorageFile
IRandomAccessStream imageStream = await imageFile.OpenAsync(FileAccessMode.Read);
System.Diagnostics.Debug.WriteLine("Original size ---> " + imageStream.ToFileSize());
//Compresses the image if it exceedes the maximum file size
imageStream.Seek(0);
BitmapDecoder compressDecoder = await BitmapDecoder.CreateAsync(imageStream);
PixelDataProvider compressionData = await compressDecoder.GetPixelDataAsync();
byte[] compressionBytes = compressionData.DetachPixelData();
//Set target compression quality
BitmapPropertySet propertySet = new BitmapPropertySet();
BitmapTypedValue qualityValue = new BitmapTypedValue(0.5, PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
imageStream.Seek(0);
imageStream = new InMemoryRandomAccessStream();
BitmapEncoder compressionEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, imageStream, propertySet);
compressionEncoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight,
compressDecoder.PixelWidth, compressDecoder.PixelHeight,
compressDecoder.DpiX, compressDecoder.DpiY, compressionBytes);
await compressionEncoder.FlushAsync();
//Create a BitmapDecoder from the stream
BitmapDecoder resizeDecoder = await BitmapDecoder.CreateAsync(imageStream);
#if DEBUG
System.Diagnostics.Debug.WriteLine("Old height and width ---> " + resizeDecoder.PixelHeight + " * " + resizeDecoder.PixelWidth + "\nCompressed size ---> " + imageStream.ToFileSize());
#endif
//Resize the image if needed
TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>();
localPage.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
const int maxImageWidth = 48;
if (resizeDecoder.PixelWidth > maxImageWidth)
{
//Resize the image if it exceedes the maximum width
int newHeight = (int)(maxImageWidth * resizeDecoder.PixelHeight / resizeDecoder.PixelWidth);
WriteableBitmap tempBitmap = new WriteableBitmap((int)resizeDecoder.PixelWidth, (int)resizeDecoder.PixelHeight);
imageStream.Seek(0);
await tempBitmap.SetSourceAsync(imageStream);
WriteableBitmap resizedImage = tempBitmap.Resize(maxImageWidth, newHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
//Assign to imageStream the resized WriteableBitmap
InMemoryRandomAccessStream resizedStream = new InMemoryRandomAccessStream();
await resizedImage.ToStream(resizedStream, BitmapEncoder.JpegEncoderId);
imageStream = resizedStream;
}
completionSource.SetResult(true);
}).Forget();
await completionSource.Task;
//Converts the final image into a Base64 String
imageStream.Seek(0);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(imageStream);
PixelDataProvider pixels = await decoder.GetPixelDataAsync();
#if DEBUG
System.Diagnostics.Debug.WriteLine("New height and width ---> " + decoder.PixelHeight + " * " + decoder.PixelWidth + "\nSize after resize ---> " + imageStream.ToFileSize());
#endif
byte[] bytes = pixels.DetachPixelData();
//Encode image
InMemoryRandomAccessStream encoded = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, decoder.PixelWidth, decoder.PixelHeight, decoder.DpiX, decoder.DpiY, bytes);
await encoder.FlushAsync();
encoded.Seek(0);
//Read bytes
byte[] outBytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(outBytes, 0, outBytes.Length);
//Create Base64
return Convert.ToBase64String(outBytes);
}注意:我使用的是TaskCompletionSource,而不是等待页面分发程序上的RunAsync调用,因为如果您使用异步操作调用它,您实际上不能等待它,因为它将任务返回给调用者,而该方法返回它而不等待要完成的操作。因此,我最终得到了内部异步操作,该操作在控件进入主方法之后仍在运行。使用该TaskCompletionSource并等待它解决问题:)
当您在异步方法中调用异步方法而不等待异步方法时,遗忘方法只是一种我必须抑制VS警告的方法。
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Forget(this IAsyncAction action) { }你可以这样称呼它:
Task<String> base64ResizedImage = Task.Run(async () => await args.Files[0].ToCompressedBase64(this));此外,如果图像的宽度超过给定值,则我的方法会调整图像大小(正如您在问题中所说的,我设置了48 )。如果您也想检查高度,只需编辑该部分并检查两个图像边界:)
https://stackoverflow.com/questions/28646132
复制相似问题