Dart加载Ui.Image时实现水平翻转 避免Canvas操作性能损耗
预加载阶段实现图片水平翻转方案
完全可以在图片加载阶段一次性完成水平翻转,后续Canvas绘制无需任何额外操作,重绘效率和普通未处理图片完全一致。注意不要直接反转压缩格式(PNG/JPG)的原始二进制字节,该操作会导致图片解码失败,必须等图片解码为原始RGBA像素数组后再做翻转处理。
修改后完整代码
import 'dart:ui' as ui; import 'package:flutter/services.dart'; static Future<ui.Image> loadFlippedImage(String imagePath) async { ByteData bd = await rootBundle.load(imagePath); final Uint8List compressedBytes = Uint8List.view(bd.buffer); final ui.Codec codec = await ui.instantiateImageCodec(compressedBytes); final ui.Image originalImage = (await codec.getNextFrame()).image; // 读取原始图片RGBA像素数据 final ByteData? originalByteData = await originalImage.toByteData( format: ui.ImageByteFormat.rawRgba ); if (originalByteData == null) { originalImage.dispose(); throw Exception('图片像素读取失败'); } final Uint8List originalPixels = originalByteData.buffer.asUint8List(); final int width = originalImage.width; final int height = originalImage.height; final int bytesPerRow = width * 4; // 每个像素占4字节(RGBA各1字节) final Uint8List flippedPixels = Uint8List(originalPixels.length); // 逐行翻转像素 for (int y = 0; y < height; y++) { final int rowStartOffset = y * bytesPerRow; for (int x = 0; x < width; x++) { // 计算原始像素和翻转后像素的对应位置 final int originalOffset = rowStartOffset + x * 4; final int flippedOffset = rowStartOffset + (width - 1 - x) * 4; // 完整复制RGBA四个通道的值 flippedPixels[flippedOffset] = originalPixels[originalOffset]; flippedPixels[flippedOffset + 1] = originalPixels[originalOffset + 1]; flippedPixels[flippedOffset + 2] = originalPixels[originalOffset + 2]; flippedPixels[flippedOffset + 3] = originalPixels[originalOffset + 3]; } } // 生成翻转后的新Image对象 final ui.Image flippedImage = await ui.Image.fromBytes( width: width, height: height, bytes: flippedPixels.buffer.asByteData(), format: ui.ImageByteFormat.rawRgba, ); // 释放原始未翻转图片的内存,避免冗余占用 originalImage.dispose(); return flippedImage; }
关键说明
- 整个翻转逻辑仅在图片加载阶段执行一次,后续Canvas绘制直接使用返回的flippedImage即可,不需要做任何矩阵变换或翻转操作,重绘效率完全满足高性能场景要求
- 该方案兼容带透明通道的图片,会完整保留Alpha通道信息
- 如果需要处理多帧动图,只需循环读取codec的所有帧,对每一帧都执行上述翻转逻辑即可
内容的提问来源于stack exchange,提问作者Johan Donkersloot
相关产品推荐
相关产品推荐

