You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter作为iOS框架时Canvas drawImage返回空白问题求助

问题解决:Flutter模块集成iOS后Canvas旋转图片返回空白

核心原因分析

你的代码中旋转时的位移计算存在错误,导致图片被绘制到了PictureRecorder的可视区域之外,最终生成空白图片。纯Flutter App可能因渲染上下文的差异未触发这个问题,但集成到iOS原生项目时,渲染裁剪逻辑更严格,错误直接显现。

具体错误点:

  • r的计算逻辑错误:原代码用sqrt(image.width * image.height + image.height * image.width) / 2,等价于sqrt(2*width*height)/2,并非图片对角线一半的正确计算方式(正确应为sqrt(image.width² + image.height²)/2)。
  • 旋转位移逻辑复杂且偏差,导致图片绘制位置完全超出录制范围。

解决方案

1. 修正旋转绘制逻辑

简化旋转位移计算,确保图片始终在PictureRecorder的可视区域内:

import 'dart:ui' as ui;
import 'package:flutter/widgets.dart';
import 'dart:math';

Future<ui.Image> rotatedImage({required ui.Image image, required double angle}) async {
  final pictureRecorder = ui.PictureRecorder();
  final canvas = Canvas(pictureRecorder);
  
  // 计算旋转后的目标画布尺寸(90/270度旋转时宽高互换)
  final int targetWidth = angle.abs() == pi / 2 ? image.height : image.width;
  final int targetHeight = angle.abs() == pi / 2 ? image.width : image.height;

  canvas.save();
  
  // 1. 将画布原点移到目标画布中心
  canvas.translate(targetWidth / 2, targetHeight / 2);
  // 2. 执行旋转操作
  canvas.rotate(angle);
  // 3. 将图片绘制到以原点为中心的位置(偏移量为负的图片宽高一半)
  canvas.drawImage(image, Offset(-image.width / 2, -image.height / 2), Paint());
  
  canvas.restore();

  final picture = pictureRecorder.endRecording();
  return await picture.toImage(targetWidth, targetHeight);
}

2. 确保在Flutter UI线程执行绘制

集成模式下,若代码由原生触发,可能运行在非UI线程,导致toImage无法正确渲染。需通过WidgetsBinding确保操作在UI线程执行:

Future<ui.Image> rotatedImage({required ui.Image image, required double angle}) async {
  final completer = Completer<ui.Image>();
  
  WidgetsBinding.instance.addPostFrameCallback((_) async {
    final pictureRecorder = ui.PictureRecorder();
    final canvas = Canvas(pictureRecorder);
    
    final targetWidth = angle.abs() == pi / 2 ? image.height : image.width;
    final targetHeight = angle.abs() == pi / 2 ? image.width : image.height;

    canvas.save();
    canvas.translate(targetWidth / 2, targetHeight / 2);
    canvas.rotate(angle);
    canvas.drawImage(image, Offset(-image.width / 2, -image.height / 2), Paint());
    canvas.restore();

    final picture = pictureRecorder.endRecording();
    final result = await picture.toImage(targetWidth, targetHeight);
    completer.complete(result);
  });
  
  return completer.future;
}

3. 优化网络图片获取(可选)

替换原getNetworkImage方法为更可靠的实现,避免集成模式下的图片上下文兼容问题:

import 'dart:typed_data';
import 'dart:io';

Future<ui.Image> getNetworkImage(String url) async {
  final httpClient = HttpClient();
  final request = await httpClient.getUrl(Uri.parse(url));
  final response = await request.close();
  final bytes = await consolidateHttpClientResponseBytes(response);
  
  final codec = await ui.instantiateImageCodec(bytes);
  final frameInfo = await codec.getNextFrame();
  return frameInfo.image;
}

验证步骤

  1. 替换rotatedImage函数为修正后的代码
  2. 确保所有Flutter UI相关操作在UI线程执行
  3. 重新编译iOS集成项目,测试旋转图片功能

内容的提问来源于stack exchange,提问作者Khang Hồ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:54:22