Xamarin UWP中BitmapEncoder.FlushAsync()无返回问题求助
PNG转JPEG时
encoder.FlushAsync()无响应的问题 在将PNG流转换为JPEG流时,程序卡在encoder.FlushAsync()处无返回、无异常;去掉await调试可通过但生成的图像损坏,添加await则应用冻结。原代码如下:
public async Task<Stream> ConvertPngToJpeg2(Stream s) { byte[] resultArray = null; //Convert stream into byte array byte[] image = new byte[s.Length]; s.Read(image, 0, image.Length); //Create An Instance of WriteableBitmap object WriteableBitmap resultBitmap = new WriteableBitmap(1, 1); using (IRandomAccessStream ms = new InMemoryRandomAccessStream()) { await ms.WriteAsync(image.AsBuffer()); ms.Seek(0); //Set the source for WriteableBitmap resultBitmap.SetSource(ms); } //Get the image data using (IRandomAccessStream ms = new InMemoryRandomAccessStream()) { try { byte[] bytes; // Open a stream to copy the image contents to the WriteableBitmap's pixel buffer using (Stream stream = resultBitmap.PixelBuffer.AsStream()) { bytes = new byte[(uint)stream.Length]; await stream.ReadAsync(bytes, 0, bytes.Length); } // Create an encoder with the Jpeg format BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ms); // WriteableBitmap uses BGRA format encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)resultBitmap.PixelWidth, (uint)resultBitmap.PixelHeight, 96, 96, bytes); //Terminate the encoder bytes await encoder.FlushAsync(); resultArray = new byte[ms.AsStream().Length]; await ms.AsStream().ReadAsync(resultArray, 0, resultArray.Length); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); } } //Store the image into memory stream Stream imgStream = new MemoryStream(resultArray); //Return the Jpeg image as stream return imgStream; }
问题原因及修复方案
核心问题点
- PNG流读取不完整:同步
s.Read无法保证读取全部字节,易导致图像数据缺失。 - WriteableBitmap加载逻辑缺陷:
SetSource是同步方法,但流写入后未确保操作完全完成,引发后续编码器处理异常。 - 编码后流读取未重置位置:
FlushAsync执行后流指针停在末尾,直接读取会获取空数据,同时引发编码器内部死锁。
修复后的代码
public async Task<Stream> ConvertPngToJpeg2(Stream s) { byte[] resultArray = null; // 异步读取完整PNG流数据 byte[] image = new byte[s.Length]; await s.ReadAsync(image, 0, image.Length); // 用BitmapDecoder异步加载图像,替代WriteableBitmap同步加载 BitmapDecoder decoder = null; using (IRandomAccessStream ms = new InMemoryRandomAccessStream()) { await ms.WriteAsync(image.AsBuffer()); ms.Seek(0); decoder = await BitmapDecoder.CreateAsync(ms); } // 处理图像编码 using (IRandomAccessStream ms = new InMemoryRandomAccessStream()) { try { BitmapFrame frame = decoder.Frames[0]; // 直接获取BGRA格式像素数据,适配JPEG编码器要求 PixelDataProvider pixelData = await frame.GetPixelDataAsync( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, new BitmapTransform(), ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); byte[] bytes = pixelData.DetachPixelData(); // 创建JPEG编码器并设置参数 BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ms); encoder.SetPixelData( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)frame.PixelWidth, (uint)frame.PixelHeight, decoder.DpiX, decoder.DpiY, bytes); // 完成编码操作 await encoder.FlushAsync(); // 重置流位置到开头,读取完整编码数据 ms.Seek(0); resultArray = new byte[(uint)ms.Size]; await ms.ReadAsync(resultArray.AsBuffer(), (uint)ms.Size, InputStreamOptions.None); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.Message); } } return new MemoryStream(resultArray); }
修复说明
- 改用
BitmapDecoder异步加载图像,彻底避免同步加载带来的流状态异常。 - 所有流操作统一使用异步方法,确保数据读写完整。
- 编码完成后重置流位置,保证能读取到完整的JPEG数据。
内容的提问来源于stack exchange,提问作者Mannu
相关产品推荐
相关产品推荐

