能否通过编程复现zathura的recolor功能并开发PDF处理工具?
编程复现Zathura的Recolor功能并生成转换后PDF
Zathura的recolor功能核心是在渲染阶段对PDF内容进行颜色映射(默认是反转颜色,也支持自定义深浅色替换),要实现输入PDF、输出处理后PDF的程序,可按以下思路操作:
1. 明确Zathura的recolor逻辑
查看Zathura源码可知,其recolor通过修改渲染时的像素颜色实现:
- 默认模式下,直接反转RGB通道值(黑↔白、浅↔深)
- 自定义模式则通过配置的
recolor-darkcolor和recolor-lightcolor做颜色替换,将原浅色区域映射为深色、深色区域映射为浅色
2. 两种实现方案
方案一:图像渲染转PDF(简单易实现)
利用PDF渲染库将每页转为图像,应用颜色映射后重新合成PDF。优点是逻辑简单,完全复现视觉效果;缺点是输出PDF为图像格式,丢失矢量可编辑性。
示例代码(Python):
import pypdfium2 as pdfium from PIL import Image import PyPDF2 import os def zathura_recolor_pdf(input_path, output_path, custom_dark=(30,30,30), custom_light=(240,240,240)): pdf = pdfium.PdfDocument(input_path) writer = PyPDF2.PdfWriter() for page_idx in range(len(pdf)): # 渲染页面为高分辨率图像 page = pdf.get_page(page_idx) bitmap = page.render(scale=2.0, rotation=0) img = bitmap.to_pil() # 实现Zathura自定义recolor逻辑:替换深浅色 def color_map(pixel): r, g, b, *a = pixel # 判断原像素是否为浅色(亮度阈值可调整) if (r + g + b) / 3 > 200: return custom_dark + tuple(a) if a else custom_dark else: return custom_light + tuple(a) if a else custom_light img = img.convert("RGBA").point(color_map) # 临时保存图像 temp_path = f"_temp_page_{page_idx}.png" img.save(temp_path) # 添加到输出PDF with open(temp_path, "rb") as f: img_pdf = PyPDF2.PdfReader(f) writer.add_page(img_pdf.pages[0]) # 保存最终PDF with open(output_path, "wb") as f: writer.write(f) # 清理临时文件 for page_idx in range(len(pdf)): os.remove(f"_temp_page_{page_idx}.png") # 使用示例:默认反转风格 zathura_recolor_pdf("input.pdf", "output_recolored.pdf") # 使用自定义深浅色 # zathura_recolor_pdf("input.pdf", "output_custom.pdf", (15,15,20), (230,230,240))
方案二:直接修改PDF矢量内容(复杂但保留矢量)
通过PDF解析库(如PyMuPDF)遍历页面中的文本、图形对象,直接修改其颜色属性。这种方法能保留PDF的矢量可编辑性,但需要处理PDF复杂的颜色空间(DeviceRGB、CMYK等)和内容流结构,适配不同类型的PDF内容难度较高。
示例思路(PyMuPDF):
import fitz def recolor_vector_pdf(input_path, output_path): doc = fitz.open(input_path) for page in doc: # 遍历页面中的文本块,修改文本颜色 for block in page.get_text("blocks"): if block[6] == 0: # 标记为文本块 rect = fitz.Rect(block[:4]) # 用白色填充背景,黑色文本模拟反转效果 page.add_redact_annot(rect, text=block[4], fill=(1,1,1), text_color=(0,0,0)) page.apply_redactions() # 遍历页面中的图形对象,反转填充/描边颜色 for shape in page.get_drawings(): # 反转填充颜色 if shape["fill"]: shape["fill"] = (1 - shape["fill"][0], 1 - shape["fill"][1], 1 - shape["fill"][2]) # 反转描边颜色 if shape["stroke"]: shape["stroke"] = (1 - shape["stroke"][0], 1 - shape["stroke"][1], 1 - shape["stroke"][2]) page.draw_shape(shape) doc.save(output_path)
注:该示例仅处理简单文本和图形,实际需适配更多PDF元素类型和颜色空间。
3. 注意事项
- 若需完全对齐Zathura的recolor效果,需严格复刻其源码中
render.c内的recolor_pixel颜色转换公式 - 图像渲染方案建议使用较高缩放比例,避免输出PDF模糊
- 矢量修改方案需处理PDF中的透明层、渐变、嵌入图像等复杂元素,需多测试不同类型的PDF文件
内容的提问来源于stack exchange,提问作者Solal Baudoin
相关产品推荐
相关产品推荐

