npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fast-watermark

v1.2.0

Published

高性能图片水印库,基于Rust + WebAssembly实现,支持文字和图片水印

Readme

fast-watermark

npm version npm downloads GitHub stars License

高性能图片水印库,基于 Rust + WebAssembly 实现,支持文字和图片水印。

✨ 特性

  • 🚀 高性能 - 基于 Rust + WebAssembly,处理速度比纯 JavaScript 快 10-100 倍
  • 🎨 文字水印 - 支持自定义字体、大小、颜色、不透明度、旋转角度
  • 🖼️ 图片水印 - 支持添加图片作为水印,可调整大小和不透明度
  • 🔄 平铺模式 - 支持水印平铺铺满整个图片
  • 📍 精确定位 - 支持精确控制水印位置和偏移
  • 📦 零依赖 - 无需额外依赖,开箱即用
  • 🌐 浏览器支持 - 完美支持现代浏览器
  • 📝 TypeScript 支持 - 完整的类型定义

📦 安装

npm install fast-watermark
# 或
yarn add fast-watermark
# 或
pnpm add fast-watermark

🚀 快速开始

基础使用

import { addWatermark, createTextWatermarkConfig } from 'fast-watermark';

// 创建文字水印配置
const config = createTextWatermarkConfig({
  text: '我的水印',
  fontSize: 30,
  fontColor: '#FFFFFF',
  transparency: 0.5,
  batch: true
});

// 添加水印
const watermarkedBlob = await addWatermark(imageFile, config);

// 转换为URL用于显示
const imageUrl = URL.createObjectURL(watermarkedBlob);

Vue 3 示例

<template>
  <div>
    <input type="file" @change="handleFileChange" accept="image/*">
    <img v-if="resultImage" :src="resultImage" alt="Watermarked Image">
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { addWatermark, createTextWatermarkConfig } from 'fast-watermark';

const resultImage = ref(null);

async function handleFileChange(event) {
  const file = event.target.files[0];
  if (!file) return;

  const config = createTextWatermarkConfig({
    text: '© 2024 My Company',
    fontSize: 24,
    fontColor: 'rgba(255, 255, 255, 0.8)',
    transparency: 0.7,
    rotate: -30,
    batch: true
  });

  const watermarkedBlob = await addWatermark(file, config);
  resultImage.value = URL.createObjectURL(watermarkedBlob);
}
</script>

React 示例

import React, { useState } from 'react';
import { addWatermark, createTextWatermarkConfig } from 'fast-watermark';

function WatermarkExample() {
  const [resultImage, setResultImage] = useState(null);

  const handleFileChange = async (event) => {
    const file = event.target.files[0];
    if (!file) return;

    const config = createTextWatermarkConfig({
      text: '© 2024 My Company',
      fontSize: 24,
      fontColor: '#FFFFFF',
      transparency: 0.7,
      rotate: -30,
      batch: true
    });

    const watermarkedBlob = await addWatermark(file, config);
    setResultImage(URL.createObjectURL(watermarkedBlob));
  };

  return (
    <div>
      <input type="file" onChange={handleFileChange} accept="image/*" />
      {resultImage && <img src={resultImage} alt="Watermarked Image" />}
    </div>
  );
}

📖 API 文档

addWatermark(image, config)

添加水印到图片(异步方式)

参数:

  • image (File | Blob | ArrayBuffer | Uint8Array) - 图片数据
  • config (WatermarkConfig) - 水印配置对象

返回:

  • Promise<Blob> - 处理后的图片 Blob 对象

示例:

const blob = await addWatermark(imageFile, config);

addWatermarkAsync(image, config)

添加水印到图片(异步方式,使用 WASM 异步函数,适合处理大文件)

参数:

  • image (File | Blob | ArrayBuffer | Uint8Array) - 图片数据
  • config (WatermarkConfig) - 水印配置对象

返回:

  • Promise<Blob> - 处理后的图片 Blob 对象

addWatermarkWithWorkers(image, config)

使用 Worker 池添加水印(多线程处理,适合批量处理)

参数:

  • image (File | Blob | ArrayBuffer | Uint8Array) - 图片数据
  • config (WatermarkConfig) - 水印配置对象

返回:

  • Promise<Blob> - 处理后的图片 Blob 对象

addWatermarkBatch(images, config)

批量处理多个图片(多线程)

参数:

  • images (Array<File | Blob | ArrayBuffer | Uint8Array>) - 图片数组
  • config (WatermarkConfig) - 水印配置对象

返回:

  • Promise<Array<Blob>> - 处理后的图片 Blob 数组

initWorkerPool(maxWorkers)

初始化 Worker 池

参数:

  • maxWorkers (number) - 最大 Worker 数量,默认为 CPU 核心数

返回:

  • Promise<void>

terminateWorkerPool()

关闭 Worker 池,释放资源

getWorkerPoolStatus()

获取 Worker 池状态

返回:

  • Object - 包含 initializedworkerCountactiveWorkersqueueLength 等信息

createTextWatermarkConfig(options)

创建文字水印配置

参数:

  • options (TextWatermarkOptions) - 配置选项

返回:

  • TextWatermarkConfig - 文字水印配置对象

示例:

const config = createTextWatermarkConfig({
  text: '水印文字',
  fontSize: 30,
  fontColor: '#FFFFFF',
  transparency: 0.5,
  rotate: 0,
  xOffset: 10,
  yOffset: 10,
  batch: false
});

createImageWatermarkConfig(options)

创建图片水印配置

参数:

  • options (ImageWatermarkOptions) - 配置选项

返回:

  • ImageWatermarkConfig - 图片水印配置对象

示例:

const config = createImageWatermarkConfig({
  imageData: 'data:image/png;base64,...',
  width: 100,
  height: 100,
  transparency: 0.5,
  rotate: 0,
  xOffset: 10,
  yOffset: 10,
  batch: false
});

isImageFile(file)

检查是否为图片文件

参数:

  • file (File | Blob | string) - 文件对象或 MIME 类型

返回:

  • boolean - 是否为图片文件

renderTextToImage(text, options)

在浏览器中将文字渲染为图片(base64)

参数:

  • text (string) - 要渲染的文字
  • options (RenderTextOptions) - 渲染选项

返回:

  • string - base64 编码的图片数据

⚙️ 配置参数

文字水印配置 (TextWatermarkConfig)

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | type | 'text' | 'text' | 水印类型(固定为 'text') | | text | string | '水印' | 水印文字内容 | | font | string | 'Arial' | 字体名称 | | font_size | number | 30 | 字体大小(像素) | | font_color | string | '#FFFFFF' | 字体颜色(十六进制或 rgba) | | transparency | number | 0.5 | 不透明度(0-1) | | rotate | number | 0 | 旋转角度(度,负值为逆时针) | | x_offset | number | 10 | X 轴偏移(像素) | | y_offset | number | 10 | Y 轴偏移(像素) | | batch | boolean | false | 是否平铺水印 | | x_count | number | - | 平铺模式下的 X 轴水印数量(优先于 x_offset) | | y_count | number | - | 平铺模式下的 Y 轴水印数量(优先于 y_offset) |

注意: createTextWatermarkConfig 函数支持驼峰命名(如 fontSizefontColor)和下划线命名(如 font_sizefont_color)两种方式。

平铺模式说明:

  • 使用 x_offset/y_offset:水印之间的间距由偏移量控制
  • 使用 x_count/y_count:水印数量固定,间距自动平分(优先级更高)

图片水印配置 (ImageWatermarkConfig)

| 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | type | 'image' | 'image' | 水印类型(固定为 'image') | | image_data | string | - | base64 编码的图片数据(必需) | | width | number | - | 水印图片宽度(可选) | | height | number | - | 水印图片高度(可选) | | transparency | number | 0.5 | 不透明度(0-1) | | rotate | number | 0 | 旋转角度(度) | | x_offset | number | 10 | X 轴偏移(像素) | | y_offset | number | 10 | Y 轴偏移(像素) | | batch | boolean | false | 是否平铺水印 | | x_count | number | - | 平铺模式下的 X 轴水印数量(优先于 x_offset) | | y_count | number | - | 平铺模式下的 Y 轴水印数量(优先于 y_offset) |

注意: createImageWatermarkConfig 函数支持驼峰命名(如 xOffsetyOffset)和下划线命名(如 x_offsety_offset)两种方式。

平铺模式说明:

  • 使用 x_offset/y_offset:水印之间的间距由偏移量控制
  • 使用 x_count/y_count:水印数量固定,间距自动平分(优先级更高)

🎯 使用场景

1. 版权保护

const config = createTextWatermarkConfig({
  text: '© 2024 My Company',
  fontSize: 20,
  fontColor: 'rgba(255, 255, 255, 0.6)',
  transparency: 0.6,
  xOffset: 20,
  yOffset: 20
});

2. 批量处理图片(推荐使用多线程)

import { addWatermarkBatch, initWorkerPool, terminateWorkerPool } from 'fast-watermark';

async function processImages(files) {
  // 初始化 Worker 池
  await initWorkerPool();

  const config = createTextWatermarkConfig({
    text: 'Processed',
    fontSize: 24,
    fontColor: '#FFFFFF',
    transparency: 0.5,
    batch: true
  });

  // 使用批量处理 API(多线程)
  const results = await addWatermarkBatch(files, config);

  // 处理完成后关闭 Worker 池
  terminateWorkerPool();

  return results;
}

3. 添加 Logo 水印

// 读取 Logo 图片并转换为 base64
const logoBase64 = await fileToBase64(logoFile);

const config = createImageWatermarkConfig({
  imageData: logoBase64,
  width: 100,
  height: 100,
  transparency: 0.8,
  xOffset: 20,
  yOffset: 20
});

const watermarked = await addWatermark(imageFile, config);

4. 全屏平铺水印

const config = createTextWatermarkConfig({
  text: 'CONFIDENTIAL',
  fontSize: 48,
  fontColor: 'rgba(255, 0, 0, 0.3)',
  transparency: 0.3,
  rotate: -45,
  batch: true,
  xOffset: 200,
  yOffset: 200
});

5. 按数量平铺水印(新功能)

使用 x_county_count 参数可以指定水印的数量,间距会自动平分:

const config = createTextWatermarkConfig({
  text: '© 2024',
  fontSize: 24,
  fontColor: '#FFFFFF',
  transparency: 0.5,
  rotate: -30,
  batch: true,
  xCount: 5,  // X轴显示5个水印
  yCount: 3   // Y轴显示3个水印
});

说明:

  • 当指定 x_county_count 时,系统会自动计算间距,使水印均匀分布
  • x_county_count 的优先级高于 x_offsety_offset
  • 如果只指定其中一个,另一个会使用默认的偏移量模式

🔧 高级用法

自定义初始化

默认情况下,WASM 模块会在第一次使用时自动初始化。你也可以手动初始化:

import { init } from 'fast-watermark';

// 手动初始化
await init();

// 或指定 WASM 文件路径
await init('/path/to/wasm_watermark_bg.wasm');

使用底层 WASM 函数

如果需要更底层的控制,可以直接使用 WASM 函数:

import { wasmFunctions, imageToUint8Array, uint8ArrayToBlob } from 'fast-watermark';

const imageBytes = await imageToUint8Array(imageFile);
const config = { /* ... */ };

// 直接调用 WASM 函数(异步)
const resultBytes = await wasmFunctions.add_watermark(imageBytes, config);
const resultBlob = uint8ArrayToBlob(resultBytes);

使用 Worker 池进行多线程处理

对于需要处理大量图片的场景,可以使用 Worker 池来避免阻塞主线程:

import {
  initWorkerPool,
  addWatermarkWithWorkers,
  getWorkerPoolStatus,
  terminateWorkerPool
} from 'fast-watermark';

// 初始化 Worker 池(指定最大 Worker 数量)
await initWorkerPool(4);

// 查看状态
console.log(getWorkerPoolStatus());
// { initialized: true, workerCount: 4, activeWorkers: 0, queueLength: 0 }

// 使用 Worker 池处理图片
const result = await addWatermarkWithWorkers(imageFile, config);

// 关闭 Worker 池
terminateWorkerPool();

📊 性能对比

基于 Rust + WebAssembly 的实现相比纯 JavaScript 实现:

  • 处理速度:快 10-100 倍
  • 内存占用:减少 50-70%
  • 文件大小:WASM 文件仅约 500KB(gzip 后约 150KB)

🌐 浏览器支持

  • Chrome/Edge 57+
  • Firefox 52+
  • Safari 11+
  • Opera 44+

📝 开发

构建项目

# 克隆仓库
git clone https://github.com/Leaderxin/fast-watermark.git
cd fast-watermark

# 安装 Rust 工具链(如果尚未安装)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# 安装 wasm-pack
cargo install wasm-pack

# 添加 wasm32 目标
rustup target add wasm32-unknown-unknown

# 构建 WASM 模块
npm run build

# 或使用开发模式构建
npm run build:dev

运行测试

npm test

🤝 贡献

欢迎贡献代码!请遵循以下步骤:

  1. Fork 本仓库
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启 Pull Request

📄 许可证

本项目采用 Apache-2.0 许可证。

🙏 致谢

📮 联系方式


Made with ❤️ using Rust + WebAssembly