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

React Native Expo如何给视频添加水印并捕获分享?

解决方案:React Native Expo 视频加水印并分享

问题根源

react-native-view-shot 仅能捕获React Native JS层渲染的视图内容,而视频组件(如expo-av的Video)属于原生层渲染,无法被快照捕获,因此会出现黑图。针对视频的水印分享需求,可根据实际场景选择以下方案:


方案1:分享带水印的视频静态截图

若需求是分享视频当前帧的截图(带水印),可通过「捕获视频帧 + 合成水印」实现:

步骤1:安装依赖

expo install expo-av expo-image-manipulator react-native-view-shot

步骤2:组件代码实现

import React, { useRef } from 'react';
import { View, Text, Image, Share, Button } from 'react-native';
import { Video } from 'expo-av';
import { captureRef } from 'react-native-view-shot';
import { manipulateAsync, SaveFormat } from 'expo-image-manipulator';

export default function PostShareComponent({ post }) {
  const viewRef = useRef(null);
  const videoRef = useRef(null);
  const watermarkRef = useRef(null);

  const share = async () => {
    if (post.type === 'photo') {
      // 保留原有照片处理逻辑
      const viewShot = await captureRef(viewRef, {
        format: 'png',
        quality: 0.8,
      });
      await Share.share({ url: viewShot });
    } else if (post.type === 'video') {
      // 1. 捕获视频当前帧截图
      const videoSnapshot = await videoRef.current.takeSnapshotAsync({
        format: 'png',
        quality: 0.8,
      });

      // 2. 捕获水印文字的视图快照
      const watermarkSnapshot = await captureRef(watermarkRef, {
        format: 'png',
        quality: 1.0,
      });

      // 3. 合成视频截图与水印(可根据实际截图尺寸调整坐标)
      const finalImage = await manipulateAsync(
        videoSnapshot,
        [
          {
            overlay: {
              uri: watermarkSnapshot,
              position: {
                x: 600 - 220, // 截图宽度 - 水印宽度 - 右边距
                y: 800 - 40,  // 截图高度 - 水印高度 - 下边距
              },
            },
          },
        ],
        { format: SaveFormat.PNG, quality: 0.8 }
      );

      // 4. 分享处理后的图片
      await Share.share({ url: finalImage.uri });
    }
  };

  return (
    <View style={{ flex: 1 }}>
      {/* 主内容视图 */}
      <View
        ref={viewRef}
        style={{ height: '100%', width: '100%', backgroundColor: 'black' }}
      >
        {post.type === 'video' ? (
          <Video
            ref={videoRef}
            source={{ uri: post.url }}
            rate={1.0}
            volume={1.0}
            isMuted={false}
            resizeMode="cover"
            shouldPlay
            isLooping
            style={{ width: '100%', height: '100%' }}
          />
        ) : (
          <Image
            source={{ uri: post.url }}
            style={{ width: '100%', height: '100%' }}
          />
        )}
      </View>

      {/* 单独的水印视图(用于捕获快照) */}
      <View
        ref={watermarkRef}
        style={{ position: 'absolute', bottom: 10, right: 10, backgroundColor: 'transparent' }}
      >
        <Text style={{ color: 'white', fontSize: 20 }}>
          SocialName.com/username
        </Text>
      </View>

      <Button title="分享" onPress={share} />
    </View>
  );
}

方案2:分享带水印的完整视频文件

若需求是分享带水印的视频本身,需使用expo-ffmpeg对视频文件进行水印添加处理:

步骤1:安装依赖

expo install expo-ffmpeg expo-file-system expo-av

步骤2:视频加水印与分享实现

import React, { useRef } from 'react';
import { View, Text, Image, Share, Button } from 'react-native';
import { Video } from 'expo-av';
import * as FileSystem from 'expo-file-system';
import * as FFmpeg from 'expo-ffmpeg';

export default function PostShareComponent({ post }) {
  const videoRef = useRef(null);

  const shareVideoWithWatermark = async () => {
    if (post.type !== 'video') return;

    // 输入视频路径与输出路径
    const inputUri = post.url;
    const outputUri = `${FileSystem.documentDirectory}watermarked_video.mp4`;

    // FFmpeg命令:添加右下角白色文字水印(字号20,边距10)
    const ffmpegCommand = `-i ${inputUri} -vf "drawtext=text='SocialName.com/username':fontsize=20:fontcolor=white:x=w-tw-10:y=h-th-10" -c:a copy ${outputUri}`;

    // 执行视频处理命令
    const result = await FFmpeg.executeAsync(ffmpegCommand);

    if (result.returnCode === 0) {
      // 分享处理后的视频
      await Share.share({ url: outputUri });
    } else {
      console.error('视频加水印失败:', result.stderr);
    }
  };

  return (
    <View style={{ flex: 1 }}>
      {post.type === 'video' ? (
        <Video
          ref={videoRef}
          source={{ uri: post.url }}
          rate={1.0}
          volume={1.0}
          isMuted={false}
          resizeMode="cover"
          shouldPlay
          isLooping
          style={{ width: '100%', height: '100%' }}
        />
      ) : (
        <Image
          source={{ uri: post.url }}
          style={{ width: '100%', height: '100%' }}
        />
      )}

      <Button title="分享带水印视频" onPress={shareVideoWithWatermark} />
    </View>
  );
}

注意事项

  • 视频处理耗时较长,建议添加加载状态提示
  • Android平台需确保文件系统权限配置正确
  • FFmpeg命令中x=w-tw-10表示水印右边距10,y=h-th-10表示下边距10(w为视频宽度,tw为文字宽度,h为视频高度,th为文字高度)

内容的提问来源于stack exchange,提问作者stormy TV

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 21:12:14