文章目录
使用pdfcpu
这个pdfcpu还是比较强大的。golang里另一个库unipdf是收费的。
##先安装中文字体
pdfcpu font install simsun.ttf
## 检查一下
pdfcpu font list
## 添加水印
pdfcpu stamp add -mode text -- "测试文字" "font:SimSun,op:0.1" ta-lib-python源码欣赏.pdf output.pdf
使用Python给PDF加水印
在Python中,我们可以使用PyPDF2
或reportlab
等库来给PDF文件添加水印。下面我将介绍两种常见的方法:
方法一:使用PyPDF2添加水印
from PyPDF2 import PdfReader, PdfWriter
def add_watermark(input_pdf, output_pdf, watermark_pdf):
# 读取原始PDF和水印PDF
pdf_reader = PdfReader(input_pdf)
watermark_reader = PdfReader(watermark_pdf)
watermark_page = watermark_reader.pages[0]
# 创建PDF写入器
pdf_writer = PdfWriter()
# 遍历每一页,添加水印
for page in pdf_reader.pages:
page.merge_page(watermark_page)
pdf_writer.add_page(page)
# 保存结果
with open(output_pdf, 'wb') as out:
pdf_writer.write(out)
# 使用示例
add_watermark('input.pdf', 'output.pdf', 'watermark.pdf')
方法二:使用reportlab创建并添加文字水印
from PyPDF2 import PdfReader, PdfWriter
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io
def create_text_watermark(text):
# 创建一个内存中的PDF水印
packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=letter)
# 设置透明度
can.setFillAlpha(0.3)
# 设置字体和大小
can.setFont("Helvetica", 60)
# 旋转45度
can.rotate(45)
# 在页面中央放置文本
can.drawString(150, 50, text)
can.save()
# 移动到开始位置
packet.seek(0)
return packet
def add_text_watermark(input_pdf, output_pdf, watermark_text):
# 创建水印PDF
watermark_packet = create_text_watermark(watermark_text)
watermark_reader = PdfReader(watermark_packet)
watermark_page = watermark_reader.pages[0]
# 读取原始PDF
pdf_reader = PdfReader(input_pdf)
# 创建PDF写入器
pdf_writer = PdfWriter()
# 合并水印到每一页
for page in pdf_reader.pages:
page.merge_page(watermark_page)
pdf_writer.add_page(page)
# 保存结果
with open(output_pdf, 'wb') as out:
pdf_writer.write(out)
# 使用示例
add_text_watermark('input.pdf', 'output.pdf', 'CONFIDENTIAL')
方法三:使用PyMuPDF(fitz)添加水印
import fitz # PyMuPDF
def add_watermark_with_fitz(input_pdf, output_pdf, watermark_text):
doc = fitz.open(input_pdf)
for page in doc:
# 插入水印文本
rect = page.rect
# 创建水印
watermark = fitz.TextWriter(page.rect)
watermark.fill_text(
page.rect, # 位置
watermark_text, # 文本
color=(0.8, 0.8, 0.8), # 浅灰色
fontsize=60, # 字体大小
rotate=45, # 旋转角度
render_mode=2 # 填充模式
)
# 将水印绘制到页面
page.write_text_writer(watermark)
doc.save(output_pdf)
# 使用示例
add_watermark_with_fitz('input.pdf', 'output.pdf', 'DRAFT')
注意事项
- 对于方法一,你需要先准备一个水印PDF文件,这个文件应该包含你想要的水印内容。
- 方法二可以动态生成文字水印,适合简单的文字水印需求。
- 方法三使用PyMuPDF,功能更强大但需要额外安装。
- 调整水印的透明度、位置、大小等参数以达到最佳效果。
- 对于大量PDF处理,考虑添加进度显示和错误处理。
要运行这些代码,你需要先安装相应的库:
pip install pypdf2 reportlab pymupdf
选择哪种方法取决于你的具体需求和水印的复杂程度。
使用Go语言给PDF添加文字水印
在Go语言中,可以使用第三方库如unidoc/unipdf
来操作PDF文件并添加水印。以下是完整的实现方法:
安装依赖
首先安装必要的库:
go get github.com/unidoc/unipdf/v3
完整代码实现
package main
import (
"fmt"
"os"
"github.com/unidoc/unipdf/v3/common/license"
"github.com/unidoc/unipdf/v3/contentstream"
"github.com/unidoc/unipdf/v3/core"
"github.com/unidoc/unipdf/v3/model"
)
// 初始化许可证(社区版有使用限制)
func init() {
// 设置社区版许可证,商业用途需要购买商业许可证
err := license.SetMeteredKey("your-license-key") // 替换为你的许可证密钥
if err != nil {
fmt.Printf("Error setting license: %v\n", err)
os.Exit(1)
}
}
func main() {
// 输入输出文件路径
inputPath := "input.pdf"
outputPath := "output.pdf"
watermarkText := "CONFIDENTIAL"
// 添加水印
err := addWatermark(inputPath, outputPath, watermarkText)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
fmt.Println("Watermark added successfully!")
}
func addWatermark(inputPath, outputPath, watermarkText string) error {
// 打开输入PDF文件
f, err := os.Open(inputPath)
if err != nil {
return err
}
defer f.Close()
// 创建PDF阅读器
pdfReader, err := model.NewPdfReader(f)
if err != nil {
return err
}
// 获取PDF页数
numPages, err := pdfReader.GetNumPages()
if err != nil {
return err
}
// 创建PDF写入器
pdfWriter := model.NewPdfWriter()
// 处理每一页
for i := 1; i <= numPages; i++ {
page, err := pdfReader.GetPage(i)
if err != nil {
return err
}
// 创建水印内容流
watermark, err := createWatermarkContentStream(watermarkText, page)
if err != nil {
return err
}
// 将水印添加到页面内容流
err = addContentStreamToPage(page, watermark)
if err != nil {
return err
}
// 将页面添加到写入器
err = pdfWriter.AddPage(page)
if err != nil {
return err
}
}
// 创建输出文件
outFile, err := os.Create(outputPath)
if err != nil {
return err
}
defer outFile.Close()
// 写入PDF文件
return pdfWriter.Write(outFile)
}
// 创建水印内容流
func createWatermarkContentStream(text string, page *model.PdfPage) (string, error) {
// 获取页面尺寸
bbox, err := page.GetMediaBox()
if err != nil {
return "", err
}
width := bbox.Urx - bbox.Llx
height := bbox.Ury - bbox.Lly
// 创建内容流
cs := contentstream.NewContentCreator()
// 设置图形状态(透明度)
cs.Add_q()
cs.Add_rg(0.8, 0.8, 0.8) // 灰色
cs.Add_gs("/GS1") // 图形状态
cs.Add_BT() // 开始文本对象
// 设置字体
font, err := model.NewStandard14Font("Helvetica")
if err != nil {
return "", err
}
// 添加字体资源
page.Resources.SetFontByName(core.PdfObjectName("F1"), font.ToPdfObject())
// 设置字体和大小
cs.Add_Tf("F1", 60) // 使用F1字体,大小60
// 计算文本位置(居中)
textWidth := float64(len(text)) * 30 // 粗略估计文本宽度
x := (width - textWidth) / 2
y := height / 2
// 设置位置并旋转45度
cs.Add_Tm(1, 0, 0, 1, x, y) // 平移
cs.Add_Tm(0.7071, 0.7071, -0.7071, 0.7071, 0, 0) // 旋转45度
// 添加文本
cs.Add_Tj(text)
// 结束文本对象
cs.Add_ET()
cs.Add_Q() // 恢复图形状态
return cs.String(), nil
}
// 将内容流添加到页面
func addContentStreamToPage(page *model.PdfPage, content string) error {
// 获取现有内容流
contentStreams, err := page.GetAllContentStreams()
if err != nil {
return err
}
// 在现有内容前添加水印内容(这样水印会显示在底层)
contentStreams = append([]string{content}, contentStreams...)
// 设置合并后的内容流
return page.SetContentStreams(contentStreams, nil)
}
代码说明
-
许可证设置:unipdf需要许可证才能使用,社区版有一些限制,商业用途需要购买商业许可证。
-
水印创建:
- 使用
contentstream.NewContentCreator()
创建PDF内容流 - 设置字体、颜色、透明度和旋转角度
- 计算水印位置使其居中显示
- 使用
-
水印添加:
- 将水印内容流添加到每一页
- 水印被添加到现有内容之前,确保不会覆盖原有内容
-
输出处理:
- 创建一个新的PDF写入器
- 将所有修改后的页面写入新文件
自定义水印样式
你可以修改createWatermarkContentStream
函数中的参数来自定义水印:
// 修改颜色(RGB值,范围0-1)
cs.Add_rg(0.5, 0, 0) // 红色
// 修改字体大小
cs.Add_Tf("F1", 40) // 字体大小40
// 修改旋转角度(示例为30度)
cos := math.Cos(30 * math.Pi / 180)
sin := math.Sin(30 * math.Pi / 180)
cs.Add_Tm(cos, sin, -sin, cos, 0, 0)
注意事项
- 对于大量PDF处理,考虑添加并发处理以提高性能
- 商业用途需要购买unipdf的商业许可证
- 水印位置和大小可能需要根据具体PDF调整
- 处理大文件时注意内存使用情况
这个实现提供了基本的文字水印功能,你可以根据需要进一步扩展,比如添加图片水印、多行水印或更复杂的水印样式。
使用C++给PDF添加文字水印
在C++中,可以使用第三方库如poppler
或PDF-Writer
来处理PDF文件并添加水印。以下是使用poppler
库的实现方法:
方法一:使用Poppler库(推荐)
安装依赖
在Linux系统上安装poppler开发包:
sudo apt-get install libpoppler-cpp-dev
完整代码实现
#include <iostream>
#include <string>
#include <poppler-document.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
#include <poppler-image.h>
#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>
using namespace std;
using namespace poppler;
void add_watermark(const string& input_file, const string& output_file, const string& watermark_text) {
// 加载PDF文档
document* doc = document::load_from_file(input_file);
if (!doc) {
cerr << "Error loading PDF file" << endl;
return;
}
// 创建PDF渲染器
page_renderer renderer;
renderer.set_render_hint(page_renderer::antialiasing, true);
renderer.set_render_hint(page_renderer::text_antialiasing, true);
// 创建输出PDF表面
cairo_surface_t* surface = cairo_pdf_surface_create(output_file.c_str(),
doc->page(0)->page_rect().width(),
doc->page(0)->page_rect().height());
cairo_t* cr = cairo_create(surface);
// 处理每一页
for (int i = 0; i < doc->pages(); ++i) {
page* pdf_page = doc->page(i);
if (!pdf_page) {
cerr << "Error loading page " << i << endl;
continue;
}
// 渲染页面到图像
image rendered_image = renderer.render_page(pdf_page);
if (rendered_image.is_null()) {
cerr << "Error rendering page " << i << endl;
continue;
}
// 获取页面尺寸
rectf page_rect = pdf_page->page_rect();
double width = page_rect.width();
double height = page_rect.height();
// 开始新页面(第一页不需要)
if (i > 0) {
cairo_show_page(cr);
}
// 绘制原始页面内容
cairo_surface_t* img_surface = cairo_image_surface_create_for_data(
const_cast<unsigned char*>(rendered_image.const_data()),
CAIRO_FORMAT_RGB24,
rendered_image.width(),
rendered_image.height(),
rendered_image.bytes_per_row());
cairo_set_source_surface(cr, img_surface, 0, 0);
cairo_paint(cr);
// 添加水印
cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 0.5); // 半透明灰色
cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 60);
// 计算文本位置(居中)
cairo_text_extents_t extents;
cairo_text_extents(cr, watermark_text.c_str(), &extents);
double x = (width - extents.width) / 2;
double y = (height - extents.height) / 2;
// 保存当前状态
cairo_save(cr);
// 平移并旋转
cairo_translate(cr, x + extents.width/2, y + extents.height/2);
cairo_rotate(cr, 45 * M_PI / 180.0);
cairo_translate(cr, -extents.width/2, -extents.height/2);
// 绘制文本
cairo_move_to(cr, 0, 0);
cairo_show_text(cr, watermark_text.c_str());
// 恢复状态
cairo_restore(cr);
// 清理
cairo_surface_destroy(img_surface);
}
// 清理资源
cairo_destroy(cr);
cairo_surface_destroy(surface);
delete doc;
}
int main() {
string input_pdf = "input.pdf";
string output_pdf = "output.pdf";
string watermark_text = "CONFIDENTIAL";
add_watermark(input_pdf, output_pdf, watermark_text);
cout << "Watermark added successfully!" << endl;
return 0;
}
编译命令
g++ -o pdf_watermark pdf_watermark.cpp `pkg-config --cflags --libs poppler-cpp cairo`
方法二:使用PDF-Writer库
安装依赖
sudo apt-get install libhpdf-dev
完整代码实现
#include <iostream>
#include <string>
#include <hpdf.h>
using namespace std;
void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
cerr << "ERROR: error_no=" << error_no << ", detail_no=" << detail_no << endl;
}
void add_watermark(const string& input_file, const string& output_file, const string& watermark_text) {
// 初始化Haru PDF库
HPDF_Doc pdf = HPDF_New(error_handler, NULL);
if (!pdf) {
cerr << "Error creating PDF document" << endl;
return;
}
// 加载现有PDF(注意:Haru本身不支持直接编辑PDF,需要先渲染再添加水印)
// 这里我们创建一个新PDF并添加水印作为示例
// 添加页面
HPDF_Page page = HPDF_AddPage(pdf);
HPDF_Page_SetSize(page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);
// 获取页面尺寸
HPDF_REAL width = HPDF_Page_GetWidth(page);
HPDF_REAL height = HPDF_Page_GetHeight(page);
// 添加一些示例内容
HPDF_Page_BeginText(page);
HPDF_Page_SetFontAndSize(page, HPDF_GetFont(pdf, "Helvetica", NULL), 12);
HPDF_Page_MoveTextPos(page, 50, height - 50);
HPDF_Page_ShowText(page, "This is a sample PDF document with watermark.");
HPDF_Page_EndText(page);
// 添加水印
HPDF_Page_BeginText(page);
HPDF_Page_SetFontAndSize(page, HPDF_GetFont(pdf, "Helvetica", NULL), 60);
HPDF_Page_SetTextRenderingMode(page, HPDF_FILL);
HPDF_Page_SetRGBFill(page, 0.8, 0.8, 0.8); // 灰色
// 计算文本位置(居中)
HPDF_REAL tw = HPDF_Page_TextWidth(page, watermark_text.c_str());
HPDF_REAL x = (width - tw) / 2;
HPDF_REAL y = height / 2;
// 设置位置并旋转
HPDF_Page_GSave(page);
HPDF_Page_Concat(page, 1, 0, 0, 1, x + tw/2, y);
HPDF_Page_Concat(page, 0.7071, 0.7071, -0.7071, 0.7071, 0, 0);
HPDF_Page_Concat(page, 1, 0, 0, 1, -tw/2, 0);
// 绘制文本
HPDF_Page_BeginText(page);
HPDF_Page_MoveTextPos(page, 0, 0);
HPDF_Page_ShowText(page, watermark_text.c_str());
HPDF_Page_EndText(page);
HPDF_Page_GRestore(page);
// 保存PDF
HPDF_SaveToFile(pdf, output_file.c_str());
HPDF_Free(pdf);
}
int main() {
string input_pdf = "input.pdf";
string output_pdf = "output.pdf";
string watermark_text = "CONFIDENTIAL";
add_watermark(input_pdf, output_pdf, watermark_text);
cout << "Watermark added successfully!" << endl;
return 0;
}
编译命令
g++ -o pdf_watermark pdf_watermark.cpp -lhpdf
注意事项
-
Poppler方法:
- 可以处理现有的PDF文件
- 需要安装poppler和cairo开发包
- 支持复杂的水印效果和透明度
-
PDF-Writer方法:
- 只能创建新PDF,不能直接编辑现有PDF
- 功能相对简单
- 如果需要编辑现有PDF,需要先解析再重建
-
其他选项:
- 商业库如PDFlib、iText等提供更完整的PDF编辑功能
- Qt框架也提供PDF处理能力
-
水印设计建议:
- 使用半透明效果避免干扰内容阅读
- 考虑旋转水印文字以防止轻易去除
- 调整字体大小和位置以适应不同页面尺寸
以上两种方法都能实现基本的PDF水印功能,选择哪种取决于你的具体需求和开发环境。