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

2023-11-14

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

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

准备

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

脚本

使用示例:

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

输出:

result

支持灵活传入页面参数
[ 4 − 8 , 12 − 17 , 20 , 24 , 27 − ] [4-8,12-17,20,24,27-] [48,1217,20,24,27]

  • 4-8、12-17:第4页到第8页、第12页到第17页
  • 20、24:第20页、第24页
  • 27-:从第27页到最后一页
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,
    )

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python调用ImageMagick生成PDF文件缩略图 的相关文章

随机推荐

  • Canoe 安装流程

    硬件 VN5620 软件 CANoe V15 0 软件 Vector License Client 6 2 驱动 Vector Driver Setup license 购买硬件时 vector会分配 参考文档 First Steps to
  • 理想方波的频谱

    1 理想方波的频谱 时域到频域 理想方波为频率1G 50 占空比 幅度为1v 上升时间为0 把理想方波通过离散傅里叶变换 DFT 就可以知道各个频率分量的幅度 如下图所示 偶次谐波如2G 4G 6G 8G 的幅度都为零 奇次谐波有如下关系式
  • 概率论--数学期望与方差--协方差(详解)

    目录 数学期望与方差 离散型随机变量的数学期望 注意 连续型随机变量的数学期望 方差 常用随机变量服从的分布 二项分布 正态分布 随机向量与随机变量的独立性 随机向量 随机变量的独立性 协方差 协方差的定义 协方差的意义 协方差矩阵 数学期
  • 软件工程专业学生的自我反思

    迷茫时的反思 我现在是一名大三的学生 有时候还是会处在一种很迷茫的状态 这种状态体现在 自己会不自觉的打开王者荣耀 打开BiliBili刷视频 熬夜看剧 慢慢地陷入一个漩涡 越陷越深 你是否经常对自己的行为感到怀疑 对自己做的事感到后悔 那
  • 关于“由于找不到MSVCP140.dll,无法继续执行代码,重新安装程序可能会解决此问题等”解决方案

    首先说明一下该问题 该问题就是表示你们的操作系统中现在确实一些必要的文件 具体是啥我也不是很清楚 然后 你现在要安装的这个软件正好要调用这些文件的一些函数 就可以简单理解为使用这些文件 需要你去安装一下这些文件 解决方案 首先 你自己去从一
  • unity点乘和叉乘的使用

    本文从http blog csdn net yupu56 article details 53609028转载而来 Unity当中经常会用到向量的运算来计算目标的方位 朝向 角度等相关数据 下面咱们来通过实例学习下Unity当中最常用的点乘
  • 星星之火-38:20M的LTE带宽,为什么是1200个子载波?

    先给个结论 在LTE中 单个小区最大的频谱带宽为20M 每个子载波的间隔为15K 带宽为30K 一共可以分为1200个子载波 那这个数据是怎么来得呢 1 15K子载波间隔的由来 如果子载波的带宽30K 那么按照频分复用FDM的规则 频谱利用
  • 春招,进阿里了....

    个人背景是东北某 985 科班本硕 做的 测试开发 有两个自己写的小项目 下面是一些印象比较深刻的面试题 阿里一面 什么是软件测试 软件测试过程中会面向哪些群体 开发一个软件都要经过哪些阶段 什么是黑盒测试 什么是白盒测试 一个测试工程师应
  • 招聘小程序制作:连接人才与企业

    随着人才市场的竞争日益激烈 招聘小程序成为了企业寻找优秀人才和求职者找到理想工作的重要工具 通过招聘小程序 企业可以发布招聘信息 筛选简历 而求职者可以浏览职位 提交简历等 招聘小程序的好处 精准匹配人才 招聘小程序通过智能推荐算法分析求职
  • 2018最新area.json(智行火车票)

    ids 5876 level 1 level4Useing name 广东省 names 广东省 notvalid pid 0 tid 5876 ids 5876 6131 level 2 level4Useing name 东莞市 nam
  • SpringBoot中搭建thymeleaf网页遇到Cannot resolve MVC View ‘###‘的问题

    原因是配置文件pom xml中thymeleaf版本与springBoot版本有冲突 要引入的thymeleaf依赖是这个
  • 使用Redis存储和使用地理空间数据

    目录 让我们回到地理空间数据 什么是Geohash Redis如何存储地理空间数据 用于处理地理空间数据的命令 通过地理空间数据读取和搜索呢 结论 众所周知 处理地理空间数据非常困难 因为纬度和经度是浮点数 应该非常精确 此外 纬度和经度似
  • 基层技术管理工作思考?

    从动机和方法两方面谈谈我的看法 动机 要做好基层技术管理工作 首先要确保自己有良好的动机 即明白自己为何要走上技术管理岗位 做管理的根本是为了获得权力 但获得权力的动机却存在很大的差别 第一种单纯是为了利己 有相当数量的人往技术管理岗位 挤
  • Electron-vue脚手架改造vue项目(2018.11.13更新)

    文章中涉及vue项目都是基于vu cli快速构建 展示的目录结构是vue cli快速构建之后的目录 Electron vue也是基于vue cli的脚手架工具 小伙伴们自己构建的vue项目想要改造成桌面应用 还请移步 Electron将We
  • 《大型网站技术架构》第二篇 架构-高可用

    高可用在公司中的重要性 对公司而言 可用性关系网站的生死存亡 对个人而言 可用性关系到自己的绩效升迁 工程师对架构做了许多优化 对代码做了很多重构 对性能 扩展性 伸缩性做了很多改善 但别人未必能直观地感受到 也许你的直接领导都不知道你做的
  • GPS采集设备命令

    经纬度简介 经度 具体来说就是地球上一个地点距离一根被称为本初子午线的南北方向走线以东或以西的度数 按国际规定英国首都伦敦格林尼治天文台原址的那一条经线定为0 经线 从0 经线算起 向东 向西各分作180 以东的180 属于东经 用 E 作
  • cURL简单使用、libcurl编程, curl_easy_setopt

    更多关于curl的信息可以参考官网http curl haxx se http curl haxx se libcurl c curl easy setopt html CURLcodecurl easy setopt CURL handl
  • Java-集合(LinkedList类)

    简单介绍 1 LinkedList底层实现了双向链表和双端队列特点 2 可以添加任意元素 元素可重复 包括null 3 线程不安全 没有实现同步 底层操作机制 1 LinkedList底层维护了一个双向链表 2 LinkedList中维护了
  • java字符串判空失败

    那你就快放弃使用 equals lkm 或 lkm isEmpty 进行判空吧 最牛逼判空方法 StringUtils isEmpty lkm 判空失败还有一种可能 基本用什么方法判空都会失败 使用String value 进行转换的判空
  • Python调用ImageMagick生成PDF文件缩略图

    使用Python调用ImageMagick生成PDF文件缩略图 Imagemagick使用Ghostscript作为其依赖项之一 以便能够处理和转换PDF相关的图像 准备 安装Ghostscript 网站 安装ImageMagick 网站