Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions WATERMARK_API_DOC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# 水印功能模块 API 文档

## 概述
水印功能模块提供了为图片添加自定义水印的能力,支持透明度、密度、字体样式、位置等多种配置选项。

## 核心类说明

### 1. WatermarkPosition.java (位置枚举)
定义水印显示位置:
- `TILED` - 平铺模式(默认)
- `TOP_LEFT` - 左上角
- `TOP_RIGHT` - 右上角
- `BOTTOM_LEFT` - 左下角
- `BOTTOM_RIGHT` - 右下角
- `CENTER` - 居中

### 2. WatermarkConfiguration.java (配置类)
水印配置类,支持链式调用:

| 方法 | 参数 | 说明 | 默认值 |
|------|------|------|--------|
| `setText(String)` | 水印文本 | 设置水印内容 | "水印" |
| `setOpacity(float)` | 0-1之间的浮点数 | 设置透明度 | 0.3f |
| `setHorizontalSpacing(int)` | 像素值 | 设置水平间距 | 200 |
| `setVerticalSpacing(int)` | 像素值 | 设置垂直间距 | 150 |
| `setFontFamily(String)` | 字体名称 | 设置字体 | "宋体" |
| `setFontSize(int)` | 字号 | 设置字体大小 | 30 |
| `setColor(Color)` | Color对象 | 设置字体颜色 | Color.GRAY |
| `setBold(Boolean)` | true/false | 是否加粗 | false |
| `setRotation(Double)` | 角度值 | 设置旋转角度 | -30.0 |
| `setPosition(WatermarkPosition)` | 位置枚举 | 设置显示位置 | TILED |

### 3. WatermarkUtil.java (工具类)
水印核心功能类,提供静态方法:

| 方法 | 说明 |
|------|------|
| `createWatermarkCanvas(width, height, config)` | 创建水印画布 |
| `createWatermarkCanvasAndStore(width, height, config, path)` | 创建水印并保存到文件 |
| `addWatermarkToImage(targetImage, config)` | 为已有图片添加水印 |
| `addWatermarkToImageAndStore(targetImage, config, outputPath)` | 为图片添加水印并保存 |
| `loadImage(path)` | 从文件加载图片 |
| `buildBytes(image)` | BufferedImage转byte数组 |
| `storeBytes(buf, fullPath)` | byte数组保存为文件 |

### 4. WatermarkPersistence.java (持久化类)
配置保存与加载功能:

| 方法 | 说明 |
|------|------|
| `saveConfiguration(config)` | 保存配置到默认文件 |
| `saveConfiguration(config, filePath)` | 保存配置到指定文件 |
| `loadConfiguration()` | 从默认文件加载配置 |
| `loadConfiguration(filePath)` | 从指定文件加载配置 |

## 使用示例

### 基本用法
```java
// 创建默认水印画布
BufferedImage watermark = WatermarkUtil.createWatermarkCanvas(800, 600, new WatermarkConfiguration());

// 保存水印图片
WatermarkUtil.createWatermarkCanvasAndStore(800, 600, new WatermarkConfiguration(), "output/watermark.png");
```

### 自定义配置
```java
WatermarkConfiguration config = new WatermarkConfiguration()
.setText("机密文件")
.setOpacity(0.5f)
.setHorizontalSpacing(150)
.setVerticalSpacing(100)
.setFontFamily("黑体")
.setFontSize(40)
.setColor(Color.RED)
.setBold(true)
.setRotation(-45.0);

BufferedImage watermark = WatermarkUtil.createWatermarkCanvas(800, 600, config);
```

### 位置模式
```java
// 左上角水印
WatermarkConfiguration config = new WatermarkConfiguration("LOGO")
.setPosition(WatermarkPosition.TOP_LEFT)
.setOpacity(0.8f)
.setRotation(0.0);

// 平铺水印
WatermarkConfiguration tiledConfig = new WatermarkConfiguration("内部使用")
.setPosition(WatermarkPosition.TILED);
```

### 给已有图片添加水印
```java
BufferedImage originalImage = WatermarkUtil.loadImage("original.png");
WatermarkConfiguration config = new WatermarkConfiguration("已审核");
BufferedImage result = WatermarkUtil.addWatermarkToImage(originalImage, config);
WatermarkUtil.storeBytes(WatermarkUtil.buildBytes(result), "watermarked.png");
```

### 配置持久化
```java
// 保存配置
WatermarkConfiguration config = new WatermarkConfiguration("我的水印").setOpacity(0.4f);
WatermarkPersistence.saveConfiguration(config);

// 加载配置
WatermarkConfiguration loadedConfig = WatermarkPersistence.loadConfiguration();
```

## 功能特点
1. **透明度控制**:支持0-1范围精确调节
2. **密度调节**:通过水平和垂直间距控制水印分布
3. **样式自定义**:支持字体、字号、颜色、加粗、旋转
4. **多种位置模式**:平铺、四角、居中共6种模式
5. **配置持久化**:本地保存用户偏好设置
6. **兼容性**:基于Java AWT实现,跨平台兼容

## 测试说明
运行单元测试类 `WatermarkTest` 可验证所有功能:
```bash
java -ea -cp out cn.localhost01.seal.WatermarkTest
```

测试输出目录:`test_output/`
4 changes: 2 additions & 2 deletions src/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ public static void main(String[] args) throws Exception {

//1.生成公章
try {
SealUtil.buildAndStoreSeal(configuration, "C:\\Users\\localhost01\\Desktop\\公章.png");
SealUtil.buildAndStoreSeal(configuration, "D:\\公章.png");
} catch (IOException e) {
e.printStackTrace();
}

//2.生成私章
SealFont font = new SealFont();
font.setFontSize(120).setBold(true).setFontText("诸葛孔明");
SealUtil.buildAndStorePersonSeal(300, 16, font, "印", "C:\\Users\\localhost01\\Desktop\\私章.png");
SealUtil.buildAndStorePersonSeal(300, 16, font, "印", "D:\\私章.png");
}

}
111 changes: 111 additions & 0 deletions src/cn/localhost01/seal/WatermarkPersistence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package cn.localhost01.seal;

import cn.localhost01.seal.configuration.WatermarkConfiguration;
import cn.localhost01.seal.configuration.WatermarkPosition;

import java.awt.*;
import java.io.*;
import java.util.Properties;

public class WatermarkPersistence {
private static final String CONFIG_FILE = "watermark_config.properties";
private static final String KEY_TEXT = "watermark.text";
private static final String KEY_OPACITY = "watermark.opacity";
private static final String KEY_HORIZONTAL_SPACING = "watermark.horizontalSpacing";
private static final String KEY_VERTICAL_SPACING = "watermark.verticalSpacing";
private static final String KEY_FONT_FAMILY = "watermark.fontFamily";
private static final String KEY_FONT_SIZE = "watermark.fontSize";
private static final String KEY_COLOR_RED = "watermark.color.red";
private static final String KEY_COLOR_GREEN = "watermark.color.green";
private static final String KEY_COLOR_BLUE = "watermark.color.blue";
private static final String KEY_IS_BOLD = "watermark.isBold";
private static final String KEY_ROTATION = "watermark.rotation";
private static final String KEY_POSITION = "watermark.position";

public static void saveConfiguration(WatermarkConfiguration config) throws IOException {
saveConfiguration(config, CONFIG_FILE);
}

public static void saveConfiguration(WatermarkConfiguration config, String filePath) throws IOException {
Properties props = new Properties();
props.setProperty(KEY_TEXT, config.getText());
props.setProperty(KEY_OPACITY, String.valueOf(config.getOpacity()));
props.setProperty(KEY_HORIZONTAL_SPACING, String.valueOf(config.getHorizontalSpacing()));
props.setProperty(KEY_VERTICAL_SPACING, String.valueOf(config.getVerticalSpacing()));
props.setProperty(KEY_FONT_FAMILY, config.getFontFamily());
props.setProperty(KEY_FONT_SIZE, String.valueOf(config.getFontSize()));
props.setProperty(KEY_COLOR_RED, String.valueOf(config.getColor().getRed()));
props.setProperty(KEY_COLOR_GREEN, String.valueOf(config.getColor().getGreen()));
props.setProperty(KEY_COLOR_BLUE, String.valueOf(config.getColor().getBlue()));
props.setProperty(KEY_IS_BOLD, String.valueOf(config.isBold()));
props.setProperty(KEY_ROTATION, String.valueOf(config.getRotation()));
props.setProperty(KEY_POSITION, config.getPosition().name());

try (OutputStream out = new FileOutputStream(filePath)) {
props.store(out, "Watermark Configuration");
}
}

public static WatermarkConfiguration loadConfiguration() throws IOException {
return loadConfiguration(CONFIG_FILE);
}

public static WatermarkConfiguration loadConfiguration(String filePath) throws IOException {
File configFile = new File(filePath);
if (!configFile.exists()) {
return new WatermarkConfiguration();
}

Properties props = new Properties();
try (InputStream in = new FileInputStream(filePath)) {
props.load(in);
}

WatermarkConfiguration config = new WatermarkConfiguration();

config.setText(props.getProperty(KEY_TEXT, "水印"));

try {
float opacity = Float.parseFloat(props.getProperty(KEY_OPACITY, "0.3"));
config.setOpacity(opacity);
} catch (NumberFormatException ignored) {}

try {
int hSpacing = Integer.parseInt(props.getProperty(KEY_HORIZONTAL_SPACING, "200"));
config.setHorizontalSpacing(hSpacing);
} catch (NumberFormatException ignored) {}

try {
int vSpacing = Integer.parseInt(props.getProperty(KEY_VERTICAL_SPACING, "150"));
config.setVerticalSpacing(vSpacing);
} catch (NumberFormatException ignored) {}

config.setFontFamily(props.getProperty(KEY_FONT_FAMILY, "宋体"));

try {
int fontSize = Integer.parseInt(props.getProperty(KEY_FONT_SIZE, "30"));
config.setFontSize(fontSize);
} catch (NumberFormatException ignored) {}

try {
int r = Integer.parseInt(props.getProperty(KEY_COLOR_RED, "128"));
int g = Integer.parseInt(props.getProperty(KEY_COLOR_GREEN, "128"));
int b = Integer.parseInt(props.getProperty(KEY_COLOR_BLUE, "128"));
config.setColor(new Color(r, g, b));
} catch (NumberFormatException ignored) {}

config.setBold(Boolean.parseBoolean(props.getProperty(KEY_IS_BOLD, "false")));

try {
double rotation = Double.parseDouble(props.getProperty(KEY_ROTATION, "-30.0"));
config.setRotation(rotation);
} catch (NumberFormatException ignored) {}

try {
String positionStr = props.getProperty(KEY_POSITION, "TILED");
config.setPosition(WatermarkPosition.valueOf(positionStr));
} catch (IllegalArgumentException ignored) {}

return config;
}
}
Loading