Flutter 如何在视频上保存(重新编码)文本叠加

Kod*_*ata 8 encode overlay flutter

我想实现像 instagram 故事(仅文本叠加)这样的功能。我能够让用户可以在视频上添加一些文本,如下面的屏幕截图(右上角的图标开始输入文本,左上角刚回到上一页)。在用户输入一些文本后,我想将视频存储到Firebase storage. 但问题是我怎样才能在视频中保留这段文字?有没有办法重写用户放置的文本覆盖文件(重新编码)?或者我是否必须将文本信息存储到数据库中然后每次都获取并显示?

在此处输入图片说明

bof*_*mer 2

我只能给出部分答案,希望对你有帮助。

您可以使用 a在 Flutter 中PictureRecorder导出 a 的位图或 png Canvas

png 图像应与源视频具有相同的大小,并且您可以使用简单的Image小部件将其覆盖在视频上。

您还可以将此 png 图像上传到 Firebase,然后在其他客户端上下载它以获得完全相同的外观(即使未安装字体)。

最酷的是,您甚至可以将手绘、贴纸、渐变和复杂形状(您可以在画布上绘制的所有内容)等内容保存在 png 图像中。

我想如果需要的话,您也可以使用某种本机库将 png 图像烘焙到视频中。

下面是一个简单的例子来展示如何生成和显示这样的 png 图像:

import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

/// @param size Video size
/// @param text Styled text
ui.Image createTextImage(Size size, TextSpan text) {
  final recorder = ui.PictureRecorder();
  final cullRect = Offset.zero & size;
  final canvas = Canvas(recorder, cullRect);

  final textPainter = TextPainter(textDirection: TextDirection.ltr, text: text);
  textPainter.layout();

  // draw text in center of canvas, you can adjust this as you like
  final textOffset = cullRect.center.translate(-textPainter.width / 2, textPainter.height / 2);
  textPainter.paint(canvas, textOffset);

  // you can also draw other geometrical shapes, gradients, paths...
  canvas.drawCircle(Offset(100.0, 100.0), 50.0, Paint()..color = Color(0xffff00ff));

  final picture = recorder.endRecording();
  final image = picture.toImage(size.width.toInt(), size.height.toInt());

  return image;
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Canvas Test',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  /// Bytes of the generated image
  Future<Uint8List> _imageBytes;

  _generateImage() {
    // Get this size from your video
    final videoSize = Size(720.0, 1280.0);

    final textStyle = TextStyle(
      fontFamily: 'Roboto',
      fontSize: 80.0,
      color: Colors.red,
    );
    final text = TextSpan(text: 'Hello World', style: textStyle);

    // Generate the image
    final imageInfo = createTextImage(videoSize, text);

    // Convert to png
    final imageBytes =
        imageInfo.toByteData(format: ui.ImageByteFormat.png).then((byteData) => Uint8List.view(byteData.buffer));

    setState(() {
      _imageBytes = imageBytes;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Canvas Test'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            FutureBuilder(
              future: _imageBytes,
              builder: (BuildContext context, AsyncSnapshot<Uint8List> snapshot) {
                if (!snapshot.hasData) return Text('No data');

                // Display the generated image in a box
                return DecoratedBox(
                  decoration: BoxDecoration(border: Border.all()),
                  child: Image.memory(
                    snapshot.data,
                    width: 180.0,
                    height: 320.0,
                  ),
                );
              },
            ),
            RaisedButton(onPressed: _generateImage, child: Text('Generate Image'))
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)