【Python自制工具软件】批量图片转PDF小工具——PIC2PDF

发布时间 2023-07-02 21:58:21作者: DMCs95

楔子

大家在工作当中总会冒出各种各样的需求,尤其当面对繁琐的工作时。

“如果有那样一款想象中的工具就好了!”可以瞬间解决手头工作的想象中的工具,是否存在呢?

当然,然而获得它总是需要我们花费大量的时间去筛选甄别,有的充斥大量广告,有的则需要付出不菲的费用。

其实完全可以自己上手来实现自己想象出的功能,做出适合自己使用的软件。过程中也可以一步一步不停的完善,将它当作一款产品去打磨。

这样有成就感的事情,其实用Python实现起来非常简单。

正好这段时间有整理照片的需求,于是就诞生了这样一款小工具。

虽然市面上很多这样类似的软件,但是自己做出来的也许更适合自己的使用习惯。

现在将代码附上,如有需要可以自行借鉴修改。

代码示例

import os
import datetime
import tkinter as tk
import tkinter.messagebox

import windnd

from tkinter import filedialog
from tkinter import ttk

from PIL import Image

# 预设转换后图片尺寸
width = 1920
height = 1080

root = tk.Tk()
root.geometry("300x120")
root.resizable(False, False)

root.title("PIC2PDF")

select_path = tk.StringVar()

width_ = tk.StringVar()
height_ = tk.StringVar()

width_.set("1920")
height_.set("1080")

dic = {"1920*1080":(1920, 1080),
    "480*640": (480, 640),
    "600*800": (600, 800),
    "1024*768": (1024, 768),
    "1152*864": (1152, 864),
    "1280*600": (1280, 600)}

# 拖拽选择功能
def dragged_files(files):
    msg = '\n'.join((item.decode('gbk') for item in files))
    select_path.set(msg)
    if msg != "":
        tkinter.messagebox.showinfo("选择完成", msg)
    else:
        tkinter.messagebox.showwarning("警告","未选择文件!")

# 多选功能
def select_files():
    select_files_path = filedialog.askopenfilenames()
    select_path.set("\n".join(select_files_path))
    if select_files_path != "":
        tkinter.messagebox.showinfo("选择完成", "\n".join(select_files_path))
    else:
        tkinter.messagebox.showwarning("警告","未选择文件!")

# 文件夹选择功能
def select_folder():
    folder_path = filedialog.askdirectory() + "/"
    select_path.set(folder_path)
    if folder_path != "/":
        tkinter.messagebox.showinfo("选择完成", folder_path)
    else:
        tkinter.messagebox.showwarning("警告","未选择文件!")


def run():
    try:
        if (width_.get(), height_.get()) != dic[combobox.get()]:
            global width, height

            width = int(width_.get())
            height = int(height_.get())

        pdfFile = os.path.dirname(select_path.get().split("\n")[0]) + "/" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".pdf"
        combine_imgs_pdf(select_path, pdfFile)
        tkinter.messagebox.showinfo("提示","转换完成")
    except (FileNotFoundError,IndexError):
        tkinter.messagebox.showwarning("警告","未找到指定文件, 请重试!")


# 转换主功能函数
def combine_imgs_pdf(folder_path, pdf_file_path):
    str_folder = folder_path.get()

    if "\n" in str_folder or str_folder[-1] != "/":
        str_folder_list = str_folder.split("\n")

        png_files = []
        sources = []
        for file in str_folder_list:
            if 'png' in file or 'jpg' in file or 'PNG' in file or 'JPG' in file:
                old_pic = Image.open(file)
                WIDTH, HEIGHT = old_pic.size
                if HEIGHT > WIDTH:
                    old_pic = old_pic.transpose(Image.ROTATE_90)
                new_image = old_pic.resize((width, height),Image.BILINEAR)
                if "/" in file:
                    i = file.rfind("/")
                else:
                    i = file.rfind("\\")

                new_image.save(file[:i+1] + "small_" + file[i+1:])
                png_files.append(file[:i+1] + "small_" + file[i+1:])

        png_files.sort()
        output = Image.open(png_files[0])
        tmp = png_files.pop(0)

        if png_files == []:
            png_file = Image.open(tmp)
            if png_file.mode == "RGBA":
                png_file = png_file.convert("RGB")
            output.save(pdf_file_path, "pdf", save_all=True, append_images=sources)
            png_file.close()
            os.remove(tmp)
        else:
            for file in png_files:
                png_file = Image.open(file)
                if png_file.mode == "RGBA":
                    png_file = png_file.convert("RGB")
                sources.append(png_file)
                output.save(pdf_file_path, "pdf", save_all=True, append_images=sources)
                os.remove(file)
            output.close()
            os.remove(tmp)


    else:
        str_folder = folder_path.get()
        files = os.listdir(str_folder)
        png_files = []
        sources = []

        for file in files:
            if 'png' in file or 'jpg' in file or 'PNG' in file or 'JPG' in file:
                old_pic = Image.open(str_folder + file)
                WIDTH, HEIGHT = old_pic.size
                if HEIGHT > WIDTH:
                    old_pic = old_pic.transpose(Image.ROTATE_90)
                new_image = old_pic.resize((width, height),Image.BILINEAR)
                new_image.save(str_folder + "small_" + file)
                png_files.append(str_folder + "small_" + file)


        png_files.sort()
        output = Image.open(png_files[0])
        tmp = png_files.pop(0)

        for file in png_files:
            png_file = Image.open(file)
            if png_file.mode == "RGBA":
                png_file = png_file.convert("RGB")
            sources.append(png_file)
            output.save(pdf_file_path, "pdf", save_all=True, append_images=sources)
            os.remove(file)
        output.close()
        os.remove(tmp)

# 尺寸选择回调函数
def callbackFunc(event):
    global width, height

    width, height = dic[combobox.get()]
    width_.set(width)
    height_.set(height)


lable = tk.Label(textvariable=tk.StringVar(value="支持文件拖拽(将根据文件名进行排序)\n图片尺寸支持自定义或选择预设尺寸\n(不建议小于原图尺寸,可能导致模糊无法辨识)"), cursor='arrow',justify="center", fg="red")
lable2 = tk.Label(textvariable=tk.StringVar(value="图片尺寸:"), cursor='arrow', justify="center")
lable3 = tk.Label(textvariable=tk.StringVar(value="*"), cursor='arrow', justify="center")
enter = tk.Entry(textvariable=width_, justify="center", relief="groove", width=5, highlightcolor="lightblue")
enter2 = tk.Entry(textvariable=height_, justify="center", relief="groove", width=5, highlightcolor="lightblue")
combobox = ttk.Combobox(root, values=["1920*1080","480*640","600*800","1024*768","1152*864","1280*600"], justify="center", state="readonly", width=10)

bt = tk.Button(text="选多文件", command=select_files, cursor='hand2', relief="groove")
bt2 = tk.Button(text="选文件夹", command=select_folder, cursor='hand2', relief="groove")
bt3 = tk.Button(text="开始转换", command=run, cursor='hand2', relief="groove", bg="lightblue")

# 控件定位
lable.place(x=14, y=0)
lable2.place(x=10, y=56)
enter.place(x=80, y=56)
lable3.place(x=118, y=56)
enter2.place(x=128, y=56)
combobox.place(x=196, y=55)
bt.place(x=10, y=84)
bt2.place(x=74, y=84)
bt3.place(x=230, y=84)


combobox.current(0)

combobox.bind("<<ComboboxSelected>>", callbackFunc)

windnd.hook_dropfiles(root, func=dragged_files)

root.mainloop()

所用第三方库均可使用 pip 进行安装

pip install pillow

pip install windnd

效果图

效果图

打包

如果想将其打包为单独的 exe 可执行文件可使用 Pyinstaller 通过以下命令实现

pyinstaller -F -w -i favicon.ico -n PIC2PDF main.py

安装 Pyinstaller

pip install Pyinstaller

创建虚拟环境

打包时请使用纯净的虚拟环境来减小打包后文件大小,可通过如下操作创建虚拟环境

在 Windows 系统下

1、通过 pip install virtualenv 安装创建虚拟环境所需要的第三方库

2、通过 virtualenv env_name 创建名为 env_name 的虚拟环境,虚拟环境将创建到当前目录下

3、激活虚拟环境:找到 env_name/Scripts/ 目录下 activate 执行,在命令行中,当前输入行前将会有 env_name 前缀表明已进入虚拟环境

4、在虚拟环境中通过 pip 安装 PyinstallerPILwindnd 成功后即可进行打包

[END]