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,
    )
相关推荐
BU摆烂会噶21 分钟前
【LangGraph】运行时上下文(Runtime Context)
人工智能·python·langchain
xingbuxing_py1 小时前
精华贴分享|北交所:小市值策略的“甜蜜陷阱”还是“弹性引擎”?——一份轻度理解
python·金融·股票·理财·量化投资·股市·炒股
yj15581 小时前
在装修预算有限的情况下,哪些地方可以省?
python
TickDB1 小时前
Python 接入国内期货 Tick 行情:从 CTP 到统一 API 的工程实践
python·websocket
趣知岛1 小时前
2026最新Python零基础入门教程,从环境搭建到实战精通(附源码)
python·青少年编程
努力努力再努力FFF2 小时前
别再乱学PS、Python了,普通大学生该看懂的技能趋势
开发语言·python
呆萌的代Ma2 小时前
docker内的n8n配置Code节点运行python代码
python·docker·容器
开源情报局4 小时前
79%的企业在用AI Agent,但只有2%规模化落地——问题出在哪?
人工智能·python
优化控制仿真模型4 小时前
2026年初中英语考纲词汇表(1600词)PDF电子版
经验分享·pdf
算法与双吉汉堡4 小时前
【Nanobot项目笔记】项目架构
python·ai·agent·智能体