【问题标题】:Photo to Base64 in Windows Phone 8.1在 Windows Phone 8.1 中将照片转换为 Base64
【发布时间】:2015-02-21 13:07:44
【问题描述】:

我正在编写一个 Windows Phone 8.1 应用程序 (WINPRT)。用户从图库中挑选照片,此图像必须上传到服务器。所以,我需要把它转换成 Base64 字符串。

所以,我关注的 Photo 到 Base64 字符串的流程是: args.Files[0] > StorageFile > IRandomAccessStream > WriteableBitmap > 像素流 > 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();    
        }

【问题讨论】:

  • 请添加有关崩溃的更多详细信息 - 什么类型的异常、异常消息等。

标签: c# windows-runtime base64 windows-phone-8.1 writeablebitmap


【解决方案1】:

你可以用我的方法压缩图片,然后转成Base64字符串。

注意:我正在使用 WriteableBitmapEx 扩展类来调整图像大小。此外,WriteableBitmap 类需要在 UI 线程上实例化,因此如果您像我一样在后台任务上运行此方法,您必须将引用传递给您所在的页面,以便该方法当它使用 WriteableBitmap 类时,将能够让当前的 UI 调度程序工作。

这里是:

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 并等待它可以解决问题:)

Forget 方法只是一种方法,当您在异步方法中调用异步方法而不等待它时,我必须抑制 VS 警告。

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Forget(this IAsyncAction action) { }

你可以这样称呼它:

Task<String> base64ResizedImage = Task.Run(async () => await args.Files[0].ToCompressedBase64(this));

另外,如果图像的宽度超过给定值,我的方法会调整图像的大小(我设置了 48,正如你在问题中所说的那样)。 如果您还想检查高度,只需编辑该部分并检查两个图像边界:)

【讨论】:

  • 亲爱的兄弟,它在 Windows Phone 8.1 WINRT(应用商店)中不起作用。实际上它的代码适用于 Windows 8.1 Silverlight。我试图修改它,但它给出了错误。你能告诉我 Windows phone 8.1 WinRT 的变化吗
  • 请求了非法状态更改。调度程序出错
  • 它仍然得到 OutOfMemoryException
  • 你错了,我的 WP8.1 应用程序中有这段代码,它运行良好,这对于 Silverlight 来说不是
  • 如果出现内存不足异常,在构造函数中声明所有 WriteableBitmap 对象!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
相关资源
最近更新 更多