前言
该工具是我认识的一位中科大的大佬在本科毕业的时候做的一个小工具,去打印店打印全彩的毕业论文的话会比较贵,他想到有没有一种方案可以实现有彩色页面的pdf和没有彩色页面的pdf分开打印,前者打印彩色,后者打印黑白,这样做的话可以节约很多打印彩色pdf页面的钱,然后这位大佬就做了这样一个小工具,省了一笔打印费,代码和原文链接在文末,我这里介绍下其大致的代码逻辑
1. is_color_image
函数
功能: 检查给定图像是否为彩色图像。
逻辑:
- 将图像转换为 RGB 模式。
- 将图像转换为 NumPy 数组,并归一化像素值到
[0,1]
范围。 - 计算每个像素的最大和最小 RGB 值。
- 计算每个像素的饱和度 (saturation)。
- 统计饱和度大于阈值 (
saturation_threshold
) 的像素占总像素的比例 (color_fraction
)。 - 如果
color_fraction
大于设定的阈值 (color_fraction_threshold
),则认为图像是彩色的。
def is_color_image(image, saturation_threshold=0.35, color_fraction_threshold=0.001):
image = image.convert('RGB')
pixels = np.array(image) / 255.0
max_rgb = np.max(pixels, axis=2)
min_rgb = np.min(pixels, axis=2)
delta = max_rgb - min_rgb
saturation = delta / (max_rgb + 1e-7) # 防止除以零
color_pixels = saturation > saturation_threshold
color_fraction = np.mean(color_pixels)
return color_fraction > color_fraction_threshold
2. is_color_page
函数
功能: 检查 PDF 页面是否为彩色页面。
逻辑:
- 将页面渲染为 pixmap 对象。
- 将 pixmap 转换为 PNG 格式的字节数据。
- 使用 PIL 库将字节数据转换为图像对象。
- 调用
is_color_image
函数检查图像是否为彩色图像。
def is_color_page(page):
pix = page.get_pixmap()
img = pix.tobytes("png")
from PIL import Image
from io import BytesIO
image = Image.open(BytesIO(img))
return is_color_image(image)
3. split_pdf
函数
功能: 将输入的 PDF 分割为彩色页面和黑白页面两个 PDF。
逻辑:
- 打开输入 PDF。
- 创建新的 PDF 对象来保存彩色页面和黑白页面。
- 遍历输入 PDF 的每一页,检查页面是否为彩色页面。
- 如果设置了双面打印 (
is_double_sized_printing
),确保彩色页面的前后页也包括在内。 - 将彩色页面和黑白页面分别插入到新的 PDF 对象中。
- 保存新的彩色和黑白 PDF。
- 关闭所有文档对象。
def split_pdf(input_pdf_path, output_color_pdf_path, output_bw_pdf_path, is_double_sized_printing):
doc = fitz.open(input_pdf_path)
color_doc = fitz.open()
bw_doc = fitz.open()
color_pages = []
bw_pages = []
for page_num in tqdm(range(len(doc))):
page = doc.load_page(page_num)
if is_color_page(page):
color_pages.append(page_num)
if is_double_sized_printing:
for page_num in color_pages:
if page_num % 2 == 0 and page_num + 1 not in color_pages and page_num + 1 < len(doc):
color_pages.append(page_num + 1)
if page_num % 2 == 1 and page_num - 1 not in color_pages and page_num - 1 > 0:
color_pages.append(page_num - 1)
for page_num in range(len(doc)):
if page_num not in color_pages:
bw_pages.append(page_num)
for page_num in sorted(color_pages):
color_doc.insert_pdf(doc, from_page=page_num, to_page=page_num)
for page_num in sorted(bw_pages):
bw_doc.insert_pdf(doc, from_page=page_num, to_page=page_num)
color_doc.save(output_color_pdf_path)
bw_doc.save(output_bw_pdf_path)
doc.close()
color_doc.close()
bw_doc.close()
主程序部分
功能: 定义输入、输出文件路径和是否双面打印的参数,并调用 split_pdf
函数。
if __name__ == '__main__':
INPUT_PDF_PATH = '1.pdf'
OUTPUT_COLOR_PDF_PATH = 'color_pages.pdf'
OUTPUT_BW_PDF_PATH = 'bw_pages.pdf'
IS_DOUBLE_SIZED_PRINTING = True
split_pdf(INPUT_PDF_PATH, OUTPUT_COLOR_PDF_PATH, OUTPUT_BW_PDF_PATH, IS_DOUBLE_SIZED_PRINTING)
完整代码
import pymupdf as fitz
import numpy as np
from tqdm import tqdm
def is_color_image(image, saturation_threshold=0.35, color_fraction_threshold=0.001):
image = image.convert('RGB')
pixels = np.array(image) / 255.0 # 归一化像素值到[0,1]范围
# 将RGB转换为HSV
max_rgb = np.max(pixels, axis=2)
min_rgb = np.min(pixels, axis=2)
delta = max_rgb - min_rgb
# 饱和度
saturation = delta / (max_rgb + 1e-7) # 防止除以零
# 判断饱和度大于阈值的彩色像素
color_pixels = saturation > saturation_threshold
color_fraction = np.mean(color_pixels)
return color_fraction > color_fraction_threshold
def is_color_page(page):
"""
Check if a page is a color page.
"""
# Render page to a pixmap
pix = page.get_pixmap()
# Convert pixmap to an image
img = pix.tobytes("png")
# Create an image object using PIL
from PIL import Image
from io import BytesIO
image = Image.open(BytesIO(img))
return is_color_image(image)
def split_pdf(input_pdf_path, output_color_pdf_path, output_bw_pdf_path, is_double_sized_printing):
# Open the input PDF
doc = fitz.open(input_pdf_path)
# Create new PDFs for color and black & white pages
color_doc = fitz.open()
bw_doc = fitz.open()
# Save color and bw pages number
color_pages = []
bw_pages = []
# Iterate over each page in the input PDF
for page_num in tqdm(range(len(doc))):
page = doc.load_page(page_num)
# Check if the page is a color page
if is_color_page(page):
color_pages.append(page_num)
# Handle double sized printing
if is_double_sized_printing:
for page_num in color_pages:
if page_num % 2 == 0 and page_num + 1 not in color_pages and page_num + 1 < len(doc):
color_pages.append(page_num + 1)
if page_num % 2 == 1 and page_num - 1 not in color_pages and page_num - 1 > 0:
color_pages.append(page_num - 1)
# Insert BW Pages
for page_num in range(len(doc)):
if page_num not in color_pages:
bw_pages.append(page_num)
# Insert PDF pages
for page_num in sorted(color_pages):
color_doc.insert_pdf(doc, from_page=page_num, to_page=page_num)
for page_num in sorted(bw_pages):
bw_doc.insert_pdf(doc, from_page=page_num, to_page=page_num)
# Save the new PDFs
color_doc.save(output_color_pdf_path)
bw_doc.save(output_bw_pdf_path)
# Close all documents
doc.close()
color_doc.close()
bw_doc.close()
if __name__ == '__main__':
INPUT_PDF_PATH = '1.pdf' # 待转换的PDF路径
OUTPUT_COLOR_PDF_PATH = 'color_pages.pdf' # 彩色部分PDF输出路径
OUTPUT_BW_PDF_PATH = 'bw_pages.pdf' # 黑白部分PDF输出路径
IS_DOUBLE_SIZED_PRINTING = True # 是否双面打印
split_pdf(INPUT_PDF_PATH, OUTPUT_COLOR_PDF_PATH, OUTPUT_BW_PDF_PATH, IS_DOUBLE_SIZED_PRINTING)
原文链接:http://t.csdnimg.cn/VY0dE
代码链接:https://github.com/RicePasteM/Color-BW-Separator-for-PDF.git
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » 通过分离有色和无色pdf页面减少打印费
发表评论 取消回复