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

Flutter中如何在图片文件上绘制文字并解决iOS端文字溢出裁剪问题

问题根因
  • 你使用的image库自带的drawString方法本身不支持自动换行,你当前是把整段文字当做单行计算宽度,当经纬度位数较多、iOS端字体渲染字符宽度和预设的Arial14字符宽度有差异时,就会出现横向超出边界被裁剪的问题
  • 你当前的宽高计算没有预留安全边距,文字直接贴在图片右下角边缘,也容易出现边缘裁剪
  • 字符宽度计算逻辑没有处理换行符,会把换行符的宽度也计入总宽度,导致最终绘制位置计算错误
解决方案

核心修改点

  1. 先预设右下角可绘制区域的安全边距,避免文字贴边
  2. 手动实现文字自动换行逻辑,按照可绘制区域的最大宽度拆分文本为多行
  3. 增加跨端渲染兼容系数,适配iOS端字体渲染的宽度差异
  4. 逐行绘制文字,计算每行的偏移量,确保所有行都在图片范围内

完整修改后代码

Future<File?> drawTextOnImage() async {
  final ImagePicker _picker = ImagePicker();
  // 拍摄照片
  final image = await _picker.pickImage(
      source: ImageSource.camera,
      maxHeight: 366,
      maxWidth: 550,
      imageQuality: 50);
  final position = await locationManager.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.high);
  if (image != null) {
    var decodeImg = UIImage.decodeImage(File(image.path).readAsBytesSync());
    final textToDraw =
        '纬度: ${position.latitude}\n经度:${position.longitude}';
    const padding = 15.0; // 右下角预留安全边距,可根据需求调整
    const font = UIImage.arial_14;
    // 计算可绘制区域的最大宽度
    final maxDrawWidth = decodeImg!.width - padding * 2;
    // 兼容iOS字体渲染的宽度系数,可根据实际渲染效果微调
    const widthScale = 1.1;

    // 自动换行拆分文本
    List<String> lines = [];
    List<String> paragraphs = textToDraw.split('\n');
    for (String para in paragraphs) {
      List<String> words = para.split(' ');
      String currentLine = '';
      double currentWidth = 0;
      for (String word in words) {
        // 计算当前单词加空格的宽度
        double wordWidth = 0;
        String wordWithSpace = word + ' ';
        for (var c in wordWithSpace.codeUnits) {
          if (font.characters.containsKey(c)) {
            wordWidth += font.characters[c]!.xadvance * widthScale;
          }
        }
        if (currentWidth + wordWidth <= maxDrawWidth) {
          currentLine += wordWithSpace;
          currentWidth += wordWidth;
        } else {
          lines.add(currentLine.trim());
          currentLine = wordWithSpace;
          currentWidth = wordWidth;
        }
      }
      if (currentLine.isNotEmpty) {
        lines.add(currentLine.trim());
      }
    }

    // 计算总文本高度
    double lineHeight = (font.lineHeight).toDouble();
    double totalTextHeight = lines.length * lineHeight;
    // 计算绘制起始点(右下角对齐)
    double startX = decodeImg.width - padding - maxDrawWidth;
    double startY = decodeImg.height - padding - totalTextHeight;

    // 逐行绘制文字
    for (int i = 0; i < lines.length; i++) {
      double lineY = startY + i * lineHeight;
      UIImage.drawString(decodeImg, font, startX.toInt(), lineY.toInt(), lines[i]);
    }

    var encodeImage = UIImage.encodeJpg(decodeImg, quality: 100);
    var finalImage = File(image.path)..writeAsBytesSync(encodeImage);
    return finalImage;
  }
  helper.ToastFlutter('获取图片失败,请重试');
  return null;
}

可选优化

如果对字体渲染一致性要求更高,可以自己加载字体文件替代库自带的Arial字体,避免不同系统自带字体差异导致的宽度计算误差。

内容的提问来源于stack exchange,提问作者Surjava Ghosh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:36:03