鸿蒙学习实战之路-PDF水印添加与删除最佳实践
最近好多朋友问我:“西兰花啊,我想给PDF文档加水印,咋搞?有时候加了水印又想删掉,这能行吗?” 害,这问题我太熟了!今天我就手把手带你搞定PDF水印的添加和删除,从文本水印到图片水印,全部给你安排得明明白白~
·
鸿蒙学习实战之路-PDF水印添加与删除最佳实践
最近好多朋友问我:“西兰花啊,我想给PDF文档加水印,咋搞?有时候加了水印又想删掉,这能行吗?” 害,这问题我太熟了!今天我就手把手带你搞定PDF水印的添加和删除,从文本水印到图片水印,全部给你安排得明明白白~
一、水印,核心接口有哪些?
PDF Kit提供了两个核心接口来处理水印:
| 接口名 | 功能描述 |
|---|---|
| addWatermark | 插入水印到PDF文档 |
| removeWatermark | 删除PDF文档水印 |
这两个接口就是咱们今天要摆弄的"印章工具",用好了,PDF文档任你盖章~
二、添加文本水印,让文档更专业
1. 基本用法
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { Font } from '@kit.ArkUI';
@Entry
@Component
struct PdfWatermarkExample {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
build() {
Column() {
// 添加文本水印
Button('添加文本水印')
.onClick(async () => {
// 确保沙箱目录有input.pdf文档
let filePath = this.context.filesDir + '/input.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
// 创建文本水印信息对象
let watermarkInfo: pdfService.TextWatermarkInfo = new pdfService.TextWatermarkInfo();
// 设置水印类型
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_TEXT;
// 设置水印内容
watermarkInfo.content = '这是水印';
// 设置字体信息
watermarkInfo.fontInfo = new pdfService.FontInfo();
let font: Font = new Font();
watermarkInfo.fontInfo.fontPath = font.getFontByName('HarmonyOS Sans').path;
// 设置水印样式
watermarkInfo.textSize = 30;
watermarkInfo.textColor = 200;
watermarkInfo.opacity = 0.5;
watermarkInfo.isOnTop = true;
watermarkInfo.rotation = 45;
watermarkInfo.scale = 1.5;
// 设置水印位置
watermarkInfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
watermarkInfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
watermarkInfo.horizontalSpace = 1.0;
watermarkInfo.verticalSpace = 1.0;
// 添加水印到第1-5页,包括奇数页和偶数页
this.pdfDocument.addWatermark(watermarkInfo, 0, 5, true, true);
// 保存文档
let outPdfPath = this.context.filesDir + '/testTextWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('添加文本水印结果:', saveResult ? '成功' : '失败');
}
// 释放资源
this.pdfDocument.releaseDocument();
})
}
}
}
2. 实际应用场景
在实际开发中,我们通常会根据不同的需求设置不同的文本水印:
// 根据文档类型设置不同的文本水印
function setupTextWatermark(pdfDoc: pdfService.PdfDocument, docType: string) {
let watermarkInfo: pdfService.TextWatermarkInfo = new pdfService.TextWatermarkInfo();
// 基础设置
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_TEXT;
watermarkInfo.fontInfo = new pdfService.FontInfo();
let font: Font = new Font();
watermarkInfo.fontInfo.fontPath = font.getFontByName('HarmonyOS Sans').path;
watermarkInfo.textSize = 30;
watermarkInfo.opacity = 0.5;
watermarkInfo.rotation = 45;
// 根据文档类型设置不同内容
switch (docType) {
case 'confidential':
watermarkInfo.content = '机密文档';
watermarkInfo.textColor = 0xFF0000; // 红色
break;
case 'draft':
watermarkInfo.content = '草稿';
watermarkInfo.textColor = 0x0000FF; // 蓝色
break;
case 'sample':
watermarkInfo.content = '样本';
watermarkInfo.textColor = 0x008000; // 绿色
break;
}
// 添加到所有页面
let pageCount = pdfDoc.getPageCount();
pdfDoc.addWatermark(watermarkInfo, 0, pageCount, true, true);
}
三、添加图片水印,让文档更个性化
1. 基本用法
// 添加图片水印
Button('添加图片水印')
.onClick(async () => {
let filePath = this.context.filesDir + '/input.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
// 创建图片水印信息对象
let watermarkInfo: pdfService.ImageWatermarkInfo = new pdfService.ImageWatermarkInfo();
// 设置水印类型
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_IMAGE;
// 设置图片路径
watermarkInfo.imagePath = this.context.filesDir + '/img.jpg';
// 设置水印样式
watermarkInfo.opacity = 0.5;
watermarkInfo.isOnTop = true;
watermarkInfo.rotation = 45;
watermarkInfo.scale = 0.5;
// 设置水印位置
watermarkInfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
watermarkInfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
watermarkInfo.horizontalSpace = 1.0;
watermarkInfo.verticalSpace = 1.0;
// 添加水印到第1-5页
this.pdfDocument.addWatermark(watermarkInfo, 0, 5, true, true);
// 保存文档
let outPdfPath = this.context.filesDir + '/testImageWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('添加图片水印结果:', saveResult ? '成功' : '失败');
}
// 释放资源
this.pdfDocument.releaseDocument();
})
四、删除水印,一键搞定
1. 基本用法
// 删除水印
Button('删除水印')
.onClick(async () => {
let filePath = this.context.filesDir + '/testTextWatermark.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
// 检查是否有水印
if (this.pdfDocument.hasWatermark()) {
// 删除水印
let removeResult = this.pdfDocument.removeWatermark();
if (removeResult) {
// 保存文档
let outPdfPath = this.context.filesDir + '/removeWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('删除水印结果:', saveResult ? '成功' : '失败');
} else {
console.log('删除水印失败');
}
} else {
console.log('文档没有水印');
}
}
// 释放资源
this.pdfDocument.releaseDocument();
})
🥦 西兰花警告
- 性能问题:addWatermark方法属于耗时操作,需要遍历每一页添加水印,页面较多时一定要放到线程里处理,不然会阻塞UI线程!
- 字体路径:添加文本水印时,字体路径一定要正确,不然会导致水印显示异常或者添加失败!
- 图片格式:添加图片水印时,要确保图片格式受支持,不然会添加失败!
- 资源释放:操作完文档一定要记得调用releaseDocument(),不然会内存泄漏!
- 页面范围:添加水印时,要注意设置正确的页面范围,避免水印添加到不需要的页面!
🥦 西兰花小贴士
- 批量处理:添加水印时,可以指定起始页和结束页,实现部分页面添加
- 奇偶页不同:通过设置oddPages和evenPages参数,可以为奇数页和偶数页设置不同的水印
- 线程处理:处理大量页面时,建议使用Worker线程,避免阻塞UI
- 预览效果:添加水印前,最好先预览一下效果,避免反复修改
- 样式统一:保持水印的样式与文档整体风格一致,增强专业性
五、常见问题与解决方案
1. 添加水印时应用卡死
问题:调用addWatermark后,应用卡死不动
解决方案:这是因为添加水印是耗时操作,需要放到线程里处理:
// 正确写法
import { worker } from '@kit.WorkerKit';
// 创建Worker来处理耗时操作
async function addWatermarkInWorker(filePath: string) {
return new Promise((resolve, reject) => {
const watermarkWorker = worker.createWorker('watermarkWorker.ts');
watermarkWorker.onmessage = (message) => {
resolve(message);
watermarkWorker.terminate();
};
watermarkWorker.onerror = (error) => {
reject(error);
watermarkWorker.terminate();
};
watermarkWorker.postMessage({ filePath });
});
}
2. 添加图片水印时失败
问题:调用addWatermark添加图片水印时,返回失败
解决方案:检查图片路径是否正确,图片格式是否受支持:
// 正确写法
let watermarkInfo: pdfService.ImageWatermarkInfo = new pdfService.ImageWatermarkInfo();
watermarkInfo.imagePath = this.context.filesDir + '/img.jpg'; // 确保图片存在
3. 删除水印时返回false
问题:调用removeWatermark时,返回false
解决方案:先检查文档是否有水印,再删除:
// 正确写法
if (this.pdfDocument.hasWatermark()) {
let removeResult = this.pdfDocument.removeWatermark();
if (removeResult) {
// 保存文档
}
}
六、完整代码示例
import { pdfService } from '@kit.PDFKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { Font } from '@kit.ArkUI';
@Entry
@Component
struct PdfWatermarkCompleteExample {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
// 添加文本水印
async addTextWatermark() {
try {
let filePath = this.context.filesDir + '/input.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let watermarkInfo: pdfService.TextWatermarkInfo = new pdfService.TextWatermarkInfo();
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_TEXT;
watermarkInfo.content = '这是水印';
// 设置字体
watermarkInfo.fontInfo = new pdfService.FontInfo();
let font: Font = new Font();
watermarkInfo.fontInfo.fontPath = font.getFontByName('HarmonyOS Sans').path;
// 设置样式
watermarkInfo.textSize = 30;
watermarkInfo.textColor = 200;
watermarkInfo.opacity = 0.5;
watermarkInfo.isOnTop = true;
watermarkInfo.rotation = 45;
watermarkInfo.scale = 1.5;
// 设置位置
watermarkInfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
watermarkInfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
watermarkInfo.horizontalSpace = 1.0;
watermarkInfo.verticalSpace = 1.0;
// 添加到所有页面
let pageCount = this.pdfDocument.getPageCount();
this.pdfDocument.addWatermark(watermarkInfo, 0, pageCount, true, true);
// 保存文档
let outPdfPath = this.context.filesDir + '/withTextWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('添加文本水印结果:', saveResult ? '成功' : '失败');
return saveResult;
} else {
console.log('加载PDF失败');
return false;
}
} catch (error) {
console.error('添加文本水印时出错:', error);
return false;
} finally {
this.pdfDocument.releaseDocument();
}
}
// 添加图片水印
async addImageWatermark() {
try {
let filePath = this.context.filesDir + '/input.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let watermarkInfo: pdfService.ImageWatermarkInfo = new pdfService.ImageWatermarkInfo();
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_IMAGE;
watermarkInfo.imagePath = this.context.filesDir + '/img.jpg';
// 设置样式
watermarkInfo.opacity = 0.5;
watermarkInfo.isOnTop = true;
watermarkInfo.rotation = 45;
watermarkInfo.scale = 0.5;
// 设置位置
watermarkInfo.verticalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_TOP;
watermarkInfo.horizontalAlignment = pdfService.WatermarkAlignment.WATERMARK_ALIGNMENT_LEFT;
watermarkInfo.horizontalSpace = 1.0;
watermarkInfo.verticalSpace = 1.0;
// 添加到所有页面
let pageCount = this.pdfDocument.getPageCount();
this.pdfDocument.addWatermark(watermarkInfo, 0, pageCount, true, true);
// 保存文档
let outPdfPath = this.context.filesDir + '/withImageWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('添加图片水印结果:', saveResult ? '成功' : '失败');
return saveResult;
} else {
console.log('加载PDF失败');
return false;
}
} catch (error) {
console.error('添加图片水印时出错:', error);
return false;
} finally {
this.pdfDocument.releaseDocument();
}
}
// 删除水印
async removeWatermark() {
try {
let filePath = this.context.filesDir + '/withTextWatermark.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
// 检查是否有水印
if (this.pdfDocument.hasWatermark()) {
// 删除水印
let removeResult = this.pdfDocument.removeWatermark();
if (removeResult) {
// 保存文档
let outPdfPath = this.context.filesDir + '/withoutWatermark.pdf';
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('删除水印结果:', saveResult ? '成功' : '失败');
return saveResult;
} else {
console.log('删除水印失败');
return false;
}
} else {
console.log('文档没有水印');
return true;
}
} else {
console.log('加载PDF失败');
return false;
}
} catch (error) {
console.error('删除水印时出错:', error);
return false;
} finally {
this.pdfDocument.releaseDocument();
}
}
build() {
Column() {
Button('添加文本水印')
.margin(10)
.onClick(async () => {
let result = await this.addTextWatermark();
if (result) {
console.log('添加文本水印成功');
} else {
console.log('添加文本水印失败');
}
})
Button('添加图片水印')
.margin(10)
.onClick(async () => {
let result = await this.addImageWatermark();
if (result) {
console.log('添加图片水印成功');
} else {
console.log('添加图片水印失败');
}
})
Button('删除水印')
.margin(10)
.onClick(async () => {
let result = await this.removeWatermark();
if (result) {
console.log('删除水印成功');
} else {
console.log('删除水印失败');
}
})
}
.padding(20)
}
}
七、实际应用案例
案例1:文档保护工具
在文档保护工具中,我们可以为敏感文档添加水印:
import { pdfService } from '@kit.PDFKit';
import { worker } from '@kit.WorkerKit';
@Entry
@Component
struct DocumentProtector {
private context = this.getUIContext().getHostContext() as Context;
// 批量添加水印
async batchAddWatermark(filePaths: string[]) {
for (let filePath of filePaths) {
console.log(`正在处理: ${filePath}`);
// 使用Worker处理耗时操作
await this.addWatermarkInWorker(filePath);
}
console.log('批量处理完成');
}
// 在Worker中处理
async addWatermarkInWorker(filePath: string) {
// 实现Worker处理逻辑
// ...
}
build() {
Column() {
Button('批量添加水印')
.onClick(async () => {
// 假设这里获取了多个PDF文件路径
let filePaths = [
this.context.filesDir + '/doc1.pdf',
this.context.filesDir + '/doc2.pdf',
this.context.filesDir + '/doc3.pdf'
];
await this.batchAddWatermark(filePaths);
})
}
}
}
案例2:文档模板生成器
在文档模板生成器中,我们可以根据用户选择的模板添加不同的水印:
import { pdfService } from '@kit.PDFKit';
@Entry
@Component
struct DocumentTemplateGenerator {
private pdfDocument: pdfService.PdfDocument = new pdfService.PdfDocument();
private context = this.getUIContext().getHostContext() as Context;
@State selectedTemplate: string = 'confidential';
// 根据模板设置水印
async generateDocumentWithWatermark(template: string) {
try {
let filePath = this.context.filesDir + '/template.pdf';
let loadResult = this.pdfDocument.loadDocument(filePath);
if (loadResult === pdfService.ParseResult.PARSE_SUCCESS) {
let watermarkInfo: pdfService.TextWatermarkInfo = new pdfService.TextWatermarkInfo();
watermarkInfo.watermarkType = pdfService.WatermarkType.WATERMARK_TEXT;
// 根据模板设置水印内容
switch (template) {
case 'confidential':
watermarkInfo.content = '机密文档';
watermarkInfo.textColor = 0xFF0000; // 红色
break;
case 'draft':
watermarkInfo.content = '草稿';
watermarkInfo.textColor = 0x0000FF; // 蓝色
break;
case 'sample':
watermarkInfo.content = '样本';
watermarkInfo.textColor = 0x008000; // 绿色
break;
}
// 设置其他属性
watermarkInfo.opacity = 0.5;
watermarkInfo.rotation = 45;
// 添加到所有页面
let pageCount = this.pdfDocument.getPageCount();
this.pdfDocument.addWatermark(watermarkInfo, 0, pageCount, true, true);
// 保存文档
let outPdfPath = this.context.filesDir + `/generated_${template}.pdf`;
let saveResult = this.pdfDocument.saveDocument(outPdfPath);
console.log('生成文档结果:', saveResult ? '成功' : '失败');
}
} catch (error) {
console.error('生成文档时出错:', error);
} finally {
this.pdfDocument.releaseDocument();
}
}
build() {
Column() {
Text('选择文档模板')
.fontSize(16)
.margin(10)
RadioGroup({
value: this.selectedTemplate
}) {
Radio({ value: 'confidential' })
.group('template')
.onChange((isChecked: boolean) => {
if (isChecked) {
this.selectedTemplate = 'confidential';
}
})
Text('机密文档')
.marginLeft(10)
Radio({ value: 'draft' })
.group('template')
.onChange((isChecked: boolean) => {
if (isChecked) {
this.selectedTemplate = 'draft';
}
})
Text('草稿')
.marginLeft(10)
Radio({ value: 'sample' })
.group('template')
.onChange((isChecked: boolean) => {
if (isChecked) {
this.selectedTemplate = 'sample';
}
})
Text('样本')
.marginLeft(10)
}
.margin(10)
Button('生成文档')
.margin(10)
.onClick(async () => {
await this.generateDocumentWithWatermark(this.selectedTemplate);
})
}
}
}
八、实用资源推荐
📚 推荐资料:
下一步行动
👉 预告:《鸿蒙学习实战之路-PDF文档书签添加与删除最佳实践》
我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦
更多推荐




所有评论(0)