给PDF添加文字水印

使用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中,我们可以使用PyPDF2reportlab等库来给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')

注意事项

  1. 对于方法一,你需要先准备一个水印PDF文件,这个文件应该包含你想要的水印内容。
  2. 方法二可以动态生成文字水印,适合简单的文字水印需求。
  3. 方法三使用PyMuPDF,功能更强大但需要额外安装。
  4. 调整水印的透明度、位置、大小等参数以达到最佳效果。
  5. 对于大量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)
}

代码说明

  1. 许可证设置:unipdf需要许可证才能使用,社区版有一些限制,商业用途需要购买商业许可证。

  2. 水印创建

    • 使用contentstream.NewContentCreator()创建PDF内容流
    • 设置字体、颜色、透明度和旋转角度
    • 计算水印位置使其居中显示
  3. 水印添加

    • 将水印内容流添加到每一页
    • 水印被添加到现有内容之前,确保不会覆盖原有内容
  4. 输出处理

    • 创建一个新的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)

注意事项

  1. 对于大量PDF处理,考虑添加并发处理以提高性能
  2. 商业用途需要购买unipdf的商业许可证
  3. 水印位置和大小可能需要根据具体PDF调整
  4. 处理大文件时注意内存使用情况

这个实现提供了基本的文字水印功能,你可以根据需要进一步扩展,比如添加图片水印、多行水印或更复杂的水印样式。

使用C++给PDF添加文字水印

在C++中,可以使用第三方库如popplerPDF-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

注意事项

  1. Poppler方法

    • 可以处理现有的PDF文件
    • 需要安装poppler和cairo开发包
    • 支持复杂的水印效果和透明度
  2. PDF-Writer方法

    • 只能创建新PDF,不能直接编辑现有PDF
    • 功能相对简单
    • 如果需要编辑现有PDF,需要先解析再重建
  3. 其他选项

    • 商业库如PDFlib、iText等提供更完整的PDF编辑功能
    • Qt框架也提供PDF处理能力
  4. 水印设计建议

    • 使用半透明效果避免干扰内容阅读
    • 考虑旋转水印文字以防止轻易去除
    • 调整字体大小和位置以适应不同页面尺寸

以上两种方法都能实现基本的PDF水印功能,选择哪种取决于你的具体需求和开发环境。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北极象

如果觉得对您有帮助,鼓励一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值