# 使用水印插件 (Beta) (/zh-CN/realtime-media/rtc/build/extensions/web/watermark)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

## 使用水印插件（Beta 版） [#使用水印插件beta-版]

水印插件可以与 Web SDK (v4.24.0 或以上) 搭配使用，用于在视频流中添加图像水印。

该插件支持自定义水印的位置、大小、透明度等属性，可以应用于本地视频轨道和远端视频轨道。

## 实现原理 [#实现原理]

声网 Web SDK 的媒体传输管道包含采集、前处理、编码、传输、解码、后处理和播放等环节。在前处理阶段，插件可以对管道中的音视频数据进行处理，从而实现虚拟背景、降噪、美颜、语音活动检测等功能。

<DocsImage alt="处理插件原理" src="https://web-cdn.agora.io/doc-cms/uploads/1728974154162-web-extension-update.png" displayWidth="90%" />

## 前提条件 [#前提条件]

使用水印插件需要满足以下前提条件：

- 使用最新版本的桌面端 Chrome（87 及以上）、Edge、Firefox 浏览器。
- 已集成 v4.24.0 或以上版本的 Web SDK，实现基础的实时音视频互动功能，具体参考[快速开始](../../../get-started/quick-start?platform=web)文档。

## 实现步骤 [#实现步骤]

按照以下步骤集成水印插件并实现视频水印功能。

### 1. 集成插件 [#1-集成插件]

通过 npm 将水印插件 [agora-extension-video-watermark](https://www.npmjs.com/package/agora-extension-video-watermark) 集成到你的项目中。

1. 运行以下命令安装水印插件：

    ```shell
    npm install agora-extension-video-watermark
    ```

2. 在你的 TypeScript 文件中加入以下代码导入水印模块：

    ```typescript
    import AgoraRTC from "agora-rtc-sdk-ng";
    import { VideoWatermarkExtension, AgoraWatermarkImage } from "agora-extension-video-watermark";
    import type { IVWProcessor } from "agora-extension-video-watermark";
    ```

### 2. 注册插件 [#2-注册插件]

调用 `AgoraRTC.registerExtensions` 方法并传入创建的 `VideoWatermarkExtension` 实例注册水印插件。

:::warning[注意]
声网推荐你只创建一个 `VideoWatermarkExtension` 实例。
:::

```typescript
import AgoraRTC from "agora-rtc-sdk-ng";
import { VideoWatermarkExtension } from "agora-extension-video-watermark";

// 创建 VideoWatermarkExtension 实例
const extension = new VideoWatermarkExtension();

// 注册插件
AgoraRTC.registerExtensions([extension]);
```

### 3. 开启插件 [#3-开启插件]

按照以下步骤开启水印插件：

1. 调用 `createProcessor` 方法创建一个 `IVWProcessor` 实例。

    ```typescript
    // 创建 IVWProcessor 实例
    const processor = extension.createProcessor();
    ```

2. 调用 SDK 的 `pipe` 方法并指定 `processorDestination` 属性，将插件注入视频处理管道。

    ```typescript
    // 创建视频轨道（本地或远端）
    const videoTrack = await AgoraRTC.createCameraVideoTrack();
    // 将插件注入视频处理管道
    videoTrack.pipe(processor).pipe(videoTrack.processorDestination);
    ```

### 4. 添加水印 [#4-添加水印]

水印插件支持两种方式创建水印图像：

#### 方式一：使用现有的 HTMLImageElement [#方式一使用现有的-htmlimageelement]

如果你已经在 DOM 中有一个图像元素（例如来自 `<img>` 标签），可以直接使用：

```typescript
const image = document.getElementById('watermark-image') as HTMLImageElement;
const watermark = new AgoraWatermarkImage(
  image,
  10,    // x 坐标
  10,    // y 坐标
  100,   // 宽度
  50,    // 高度
  0.8    // 透明度 (0.0-1.0)
);

// 添加水印到处理器
processor.addVideoWatermark(watermark);
```

#### 方式二：使用图像 URL（异步） [#方式二使用图像-url异步]

你也可以通过图像 URL 创建水印。这种方式会异步加载图像，因此必须等待 `.ready` Promise 完成后才能使用：

```typescript
const watermark = new AgoraWatermarkImage(
  'https://example.com/watermark.png',
  10,    // x 坐标
  10,    // y 坐标
  100,   // 宽度（-1 表示使用图像原始宽度）
  50,    // 高度（-1 表示使用图像原始高度）
  0.8    // 透明度 (0.0-1.0)
);

// 等待图像加载完成
await watermark.ready;

// 添加水印到处理器
processor.addVideoWatermark(watermark);
```

:::warning[注意]
- 使用 URL 加载图像时，可能会因为 [跨域资源策略 (CORP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cross-Origin_Resource_Policy) 限制而失败。如果图像加载失败，`ready` Promise 将被拒绝并返回错误。
- 如果 `width` 和 `height` 设置为 -1，它们将在图像加载后设置为图像的原始宽度和高度。
:::

### 5. 启用处理器 [#5-启用处理器]

添加水印后，调用 `enable` 方法启用处理器：

```typescript
const enable = async () => {
  const enabled = processor.enabled;
  if (!enabled) {
    await processor.enable();
  }
};

await enable();
```

### 6. 管理水印 [#6-管理水印]

你可以动态地启用或禁用水印处理器：

```typescript
// 启用水印
const enable = async () => {
  const enabled = processor.enabled;
  if (!enabled) {
    await processor.enable();
  }
};

// 禁用水印
const disable = async () => {
  const enabled = processor.enabled;
  if (enabled) {
    await processor.disable();
  }
};
```

### 7. 释放资源 [#7-释放资源]

当不再需要使用水印插件时，需要正确释放资源：

```typescript
const release = async () => {
  // 取消管道连接
  processor.unpipe();
  videoTrack.unpipe();
  
  // 重新连接到原始目标
  videoTrack.pipe(videoTrack.processorDestination);
  
  // 释放处理器资源
  await processor.release();
};

await release();
```

## 完整示例 [#完整示例]

以下是一个完整的水印插件使用示例：

```typescript
import AgoraRTC from "agora-rtc-sdk-ng";
import { VideoWatermarkExtension, AgoraWatermarkImage } from "agora-extension-video-watermark";
import type { IVWProcessor } from "agora-extension-video-watermark";

// 创建并注册水印插件
const extension = new VideoWatermarkExtension();
AgoraRTC.registerExtensions([extension]);

// 创建处理器
const processor = extension.createProcessor();

async function setupWatermark() {
  try {
    // 创建视频轨道
    const videoTrack = await AgoraRTC.createCameraVideoTrack();
    
    // 将插件注入视频处理管道
    videoTrack.pipe(processor).pipe(videoTrack.processorDestination);
    
    // 创建水印（使用 URL 方式）
    const watermark = new AgoraWatermarkImage(
      'https://example.com/logo.png',
      20,   // x 坐标
      20,   // y 坐标
      120,  // 宽度
      60,   // 高度
      0.7   // 透明度
    );
    
    // 等待水印图像加载完成
    await watermark.ready;
    
    // 添加水印到处理器
    processor.addVideoWatermark(watermark);
    
    // 启用处理器
    await processor.enable();
    
    console.log("水印插件已成功启用");
    
    // 播放视频轨道
    videoTrack.play("video-container");
    
  } catch (error) {
    console.error("设置水印时出错:", error);
  }
}

// 清理资源的函数
async function cleanup() {
  try {
    await processor.disable();
    processor.unpipe();
    videoTrack.unpipe();
    videoTrack.pipe(videoTrack.processorDestination);
    await processor.release();
    console.log("资源已清理");
  } catch (error) {
    console.error("清理资源时出错:", error);
  }
}

// 调用设置函数
setupWatermark();
```

## API 参考 [#api-参考]

本节提供水印插件的核心 API 参考。

### addVideoWatermark [#addvideowatermark]

```typescript
addVideoWatermark(watermark: AgoraWatermarkImage): number;
```

向视频流添加水印图像。

**参数：**

- `watermark`：`AgoraWatermarkImage` 实例。

**返回值：**

返回水印的 ID 表示标识，用于后续水印管理。如果返回 -1，则表示添加失败。

### clearVideoWatermarks [#clearvideowatermarks]

```typescript
clearVideoWatermarks(): boolean;
```

删除所有已添加的视频水印。

**返回值：**

- `true`：成功删除所有水印。
- `false`：删除失败。

### removeVideoWatermark [#removevideowatermark]

```typescript
removeVideoWatermark(id: number): boolean;
```

根据水印的 ID 删除指定的视频水印。

**参数：**

- `id`：要删除的水印 ID。

**返回值：**

- `true`：成功删除指定水印。
- `false`：删除失败。

### release [#release]

```typescript
release(): Promise<void>;
```

释放 `IVWProcessor` 资源。

### AgoraWatermarkImage [#agorawatermarkimage]

```typescript
export class AgoraWatermarkImage {
  public image: HTMLImageElement | null;
  public x: number;
  public y: number;
  public width: number;
  public height: number;
  public alpha: number;

  public ready: Promise<void>;
  public imageReady: boolean = false;
}
```

**参数：**

- `image`：用作水印的 HTMLImageElement。如果为 `null`，则不使用图像。
- `url`：用作水印的图像 URL。如果为 `null` 或空字符串，则不使用图像。
- `x`：图像在视频上的 x 坐标（像素），相对于左上角。默认为 0。
- `y`：图像在视频上的 y 坐标（像素），相对于左上角。默认为 0。
- `width`：水印图像的期望宽度（像素）。默认为 -1，表示使用图像加载后的原始宽度。
- `height`：水印图像的期望高度（像素）。默认为 -1，表示使用图像加载后的原始高度。
- `alpha`：图像不透明度，从 0.0（完全透明）到 1.0（完全不透明）。默认为 1.0。
