iOS平台Dart/Flutter中dart:ui.Image的toByteData方法性能问题求助
临时解决方案:iOS上dart:ui.Image转PNG字节数据优化
针对iOS上dart:ui.Image.toByteData(format: ImageByteFormat.png)的性能问题,在官方修复合并前,你可以尝试以下几种临时解决方案:
1. 使用image包进行纯Dart编码
通过先将dart:ui.Image转换为image库的Image对象,再用该库的PNG编码方法替代原生实现,能显著提升速度。
步骤:
- 添加依赖到
pubspec.yaml:
dependencies: image: ^4.0.17 # 或最新版本
- 转换与编码代码:
import 'dart:ui' as ui; import 'package:image/image.dart' as img; // 将dart:ui.Image转换为image库的Image对象 img.Image _convertUiImageToImage(ui.Image uiImage) { final ui.ByteData? rawByteData = uiImage.toByteData(format: ui.ImageByteFormat.rawRgba); if (rawByteData == null) throw Exception('Failed to retrieve raw image data'); final Uint8List pixels = rawByteData.buffer.asUint8List(); return img.Image.fromBytes( width: uiImage.width, height: uiImage.height, bytes: pixels.buffer, format: img.Format.rgba, ); } // 编码为PNG字节数据 Uint8List encodeUiImageToPng(ui.Image uiImage) { final img.Image image = _convertUiImageToImage(uiImage); return img.encodePng(image); }
说明:
rawRgba格式的转换远快于直接转PNG,再通过image库优化后的PNG编码逻辑,能大幅缩短耗时,且无需编写原生代码。
2. 通过原生通道(MethodChannel)实现iOS端编码
直接调用iOS系统API进行PNG编码,绕过Flutter引擎当前的性能瓶颈。
Dart端代码:
import 'dart:ui' as ui; import 'package:flutter/services.dart'; final MethodChannel _imageEncoderChannel = MethodChannel('com.example.image_encoder'); Future<Uint8List?> encodeUiImageToPngNative(ui.Image uiImage) async { try { final ui.ByteData? rawData = uiImage.toByteData(format: ui.ImageByteFormat.rawRgba); if (rawData == null) return null; final Uint8List pixels = rawData.buffer.asUint8List(); return await _imageEncoderChannel.invokeMethod<Uint8List>( 'encodeToPng', { 'width': uiImage.width, 'height': uiImage.height, 'pixels': pixels, }, ); } on PlatformException catch (e) { print('PNG encoding failed: ${e.message}'); return null; } }
iOS端Swift代码:
- 创建编码器处理类:
import UIKit import Flutter class ImageEncoderHandler: NSObject, FlutterPlugin { static func register(with registrar: FlutterPluginRegistrar) { let channel = FlutterMethodChannel(name: "com.example.image_encoder", binaryMessenger: registrar.messenger()) let instance = ImageEncoderHandler() registrar.addMethodCallDelegate(instance, channel: channel) } func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { guard call.method == "encodeToPng" else { result(FlutterMethodNotImplemented) return } guard let args = call.arguments as? [String: Any], let width = args["width"] as? Int, let height = args["height"] as? Int, let pixelData = args["pixels"] as? Data else { result(FlutterError(code: "InvalidArgs", message: "Missing or invalid arguments", details: nil)) return } // 创建CGImage并编码为PNG let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue) guard let context = CGContext( data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: width * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue ) else { result(FlutterError(code: "ContextError", message: "Failed to create CGContext", details: nil)) return } context.data?.copyMemory(from: pixelData.baseAddress!, byteCount: pixelData.count) guard let cgImage = context.makeImage() else { result(FlutterError(code: "ImageError", message: "Failed to create CGImage", details: nil)) return } let uiImage = UIImage(cgImage: cgImage) guard let pngData = uiImage.pngData() else { result(FlutterError(code: "EncodeError", message: "Failed to encode PNG", details: nil)) return } result(pngData) } }
- 在
AppDelegate中注册通道:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { ImageEncoderHandler.register(with: self.registrar(forPlugin: "ImageEncoderHandler")) GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) }
说明:
直接调用iOS系统的UIImage.pngData()方法,性能优于当前Flutter引擎的实现,但需要维护原生代码。
3. 提前压缩图片
如果业务允许,在获取dart:ui.Image前先压缩图片的尺寸或质量,从根源减少转换耗时:
- 加载本地/网络图片时,使用支持压缩的库(如
image_picker、cached_network_image)设置压缩参数 - 用
image库对图片进行缩放、质量压缩后再转换为dart:ui.Image
内容的提问来源于stack exchange,提问作者Atreidex
相关产品推荐
相关产品推荐

