Python调用ImageMagick生成PDF文件缩略图

使用Python调用ImageMagick生成PDF文件缩略图

Imagemagick使用Ghostscript作为其依赖项之一,以便能够处理和转换PDF相关的图像。

准备

安装完毕后,需要自行配置环境路径

脚本

使用示例:

powershell 复制代码
python .\get_thumbnail.py --filepath .\paper.pdf --page [4-8,12-17,20,24,27-] --output-dir test-dir

输出:

支持灵活传入页面参数

4 − 8 , 12 − 17 , 20 , 24 , 27 − \] \[4-8,12-17,20,24,27-\] \[4−8,12−17,20,24,27−

  • 4-8、12-17:第4页到第8页、第12页到第17页
  • 20、24:第20页、第24页
  • 27-:从第27页到最后一页
python 复制代码
import subprocess
import argparse
from pathlib import Path
from math import sqrt

# 解析参数
parser = argparse.ArgumentParser()
parser.add_argument("--filepath", type=str, help="pdf文件路径")
parser.add_argument(
    "--page",
    type=str,
    default="all",
    help="指定要生成缩略图的pdf文件页面 e.[1-3,8,10,27-] 默认为全部页面",
)
parser.add_argument("--shape", type=str, default="cube", help="指定缩略图的形状 e.[8x3] 默认为正方形")
parser.add_argument("--output-dir", type=str, default="./images", help="指定输出文件夹")
args = parser.parse_args()


# 写一个函数,调用外部程序获取pdf文件总页数
def get_file_page_num(filepath: str):
    result = subprocess.run(
        ["magick", "identify", "-format", "%n", filepath], stdout=subprocess.PIPE
    )
    # 获取命令行输出
    output = result.stdout.decode("utf-8")
    for i in range(1, 4):
        if len(output) == i * int(output[:i]):
            return int(output[:i])


# 预处理参数
# 获取目标页面总数目以及详细页码
def get_dst_page(filepath: str, page_str: str):
    total_num = 0
    detail_page = []
    if page_str == "all":
        total_num = get_file_page_num(filepath)
        detail_page.append((1, total_num))
    else:
        for item in page_str.replace(" ", "")[1:-1].split(","):
            if "-" not in item:
                total_num += 1
                detail_page.append(int(item))
            if "-" in item and not item.endswith("-"):
                start, end = list(map(lambda x: int(x), item.split("-")))
                total_num += end - start + 1
                detail_page.append((start, end))
            if "-" in item and item.endswith("-"):
                start = int(item[:-1])
                end = get_file_page_num(filepath)
                total_num += end - start
                detail_page.append((start, end - 1))
    return total_num, detail_page


def get_per_page_idx(detail_page_scope: list):
    pages = []
    for item in detail_page_scope:
        if isinstance(item, tuple):
            for i in range(item[0], item[1] + 1):
                pages.append(i)
        else:
            pages.append(item)
    return pages


# 自动推断比较合适的形状
def infer_shape(num):
    H = int(sqrt(num / sqrt(2)))
    W = int(num / H + 1)
    if H * W < num:
        H += 1
    return W, H


def get_shape(num):
    if args.shape == "cube":
        shape = infer_shape(num)
        return f"{shape[0]}x{shape[1]}"
    else:
        return args.shape.replace(" ", "")


if __name__ == "__main__":
    if not Path(args.output_dir).exists():
        Path(args.output_dir).mkdir()
    total_num, detail_page = get_dst_page(args.filepath, args.page)
    # 调用外部程序将每个指定的页面转换为缩略图
    # 必须指定"-alpha remove",否则生成的图片背景永远是黑色
    for item in detail_page:
        if isinstance(item, tuple):
            subprocess.run(
                [
                    "magick",
                    "convert",
                    "-thumbnail",
                    "x800",
                    "-alpha",
                    "remove",
                    f"{args.filepath}[{item[0]}-{item[1]}]",
                    str(Path(args.output_dir) / "output.png"),
                ],
                shell=True,
            )
        else:
            subprocess.run(
                [
                    "magick",
                    "convert",
                    "-thumbnail",
                    "x800",
                    "-alpha",
                    "remove",
                    f"{args.filepath}[{item}]",
                    str(Path(args.output_dir) / f"output-{item}.png"),
                ],
                shell=True,
            )

    print("参与生成缩略图的页面为:", get_per_page_idx(detail_page))
    image_list = list(
        map(
            lambda x: str(Path(args.output_dir) / f"output-{x}.png"),
            get_per_page_idx(detail_page),
        )
    )
    # 调用外部程序合并缩略图
    subprocess.run(
        [
            "magick",
            "montage",
            *image_list,
            "-geometry",
            "+0+0",
            "-border",
            "3",
            "-bordercolor",
            "black",
            "-tile",
            f"{get_shape(total_num)}",
            str(Path(args.output_dir) / "result.jpg"),
        ],
        shell=True,
    )
相关推荐
zone773911 小时前
001:简单 RAG 入门
后端·python·面试
F_Quant11 小时前
🚀 Python打包踩坑指南:彻底解决 Nuitka --onefile 配置文件丢失与重启报错问题
python·操作系统
允许部分打工人先富起来12 小时前
在node项目中执行python脚本
前端·python·node.js
IVEN_12 小时前
Python OpenCV: RGB三色识别的最佳工程实践
python·opencv
haosend13 小时前
AI时代,传统网络运维人员的转型指南
python·数据网络·网络自动化
曲幽13 小时前
不止于JWT:用FastAPI的Depends实现细粒度权限控制
python·fastapi·web·jwt·rbac·permission·depends·abac
IVEN_1 天前
只会Python皮毛?深入理解这几点,轻松进阶全栈开发
python·全栈
Ray Liang1 天前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
AI攻城狮1 天前
如何给 AI Agent 做"断舍离":OpenClaw Session 自动清理实践
python
千寻girling1 天前
一份不可多得的 《 Python 》语言教程
人工智能·后端·python