基於Python PIL實現簡單圖片格式轉化器


基於Python PIL實現簡單圖片格式轉化器

1、簡介

*提示:閱讀本文,默認你對Python有一定了解,並且安裝有PIL,對tkinter有一定使用基礎。文中所有代碼皆在Python3版本上實現,請務必注意*

Pyhton PIL庫提供了許多圖片處理功能,理論上可以借助此完成圖片格式轉換功能,在配合Python tkinter庫繪制前端頁面,基本上可以實現一個簡單圖片格式轉換器

2、前期資料准備

2.1邏輯支持

2.1.1如何實現圖片格式轉換?

​ Python PIL庫提供了許多圖片處理功能,現在我們只需要其中一個功能:圖片格式轉換支持我們實現我們的圖片格式轉換器。具體如下:

from PIL import Image	# 引入PIL Image提供圖片格式轉換功能
file_path = 'D:/test/test.png' #測試圖片
photo = Image.open(file_path)
photo.save('D:/test/new_test.gif')	# save會根據后綴名轉換為特定格式

注意:在轉換為.jgp格式圖片時,需要將圖片模式轉換為RGB模式,即在save語句之前加上:photo = photo.convert('RGB') 更多參考PIL save語句說明

​ 當然,這里我們必須聲明一點:PIL提供的格式轉換支持是有限的,具體參考PIL支持圖片格式

2.1.2如何保存需要大小的圖片?

​ 具體參考:

from PIL import Image	# 引入PIL Image提供圖片格式轉換功能
file_path = 'D:/test/test.png' #測試圖片
photo = Image.open(file_path)
photo = photo.resize((200,300)) # 將圖片大小轉換為(width,height)200x300大小
photo.save('D:/test/new_test.gif')	# save會根據后綴名轉換為特定格式

​ 到此,邏輯支持部分基本上夠我們實現后端的圖片格式轉換了。

2.2前端頁面支持

​ 前端窗口大致上如下圖所示:

​ 這里強調一下基本的頁面構成:圖片預覽、轉換格式下拉選擇(當然,這個格式是可控的,我們可以添加自己需要的格式,前提是在PIL支持的格式轉換范圍)、圖片選擇按鈕、轉換大小選擇和保存圖片按鈕。

​ 當然,需要強調的一點,在圖片選擇和保存的過程中,我們添加了tkinter中的messagebox組件來提示用戶可能出現的錯誤操作。

​ 下面將簡單的介紹一下容易出現錯誤的組件。

2.2.1預覽圖片

​ 我們通過一個Label組件實現預覽需要轉換的圖片,為Label中image屬性添加為要加載的圖片。這里,我們使用PIL中的ImageTk.PhotoImage來加載預覽圖片,而不tkinter.PhotoImage,主要目的是為了使用Image來裁剪圖片來保證預覽圖片大小一致,防止圖片顯示不完全。具體參考下面的例子:

import tkinter
from PIL import Image, ImageTk

file_path = 'D:/test/test.png'

root = tkinter.Tk()

photo = ImageTk.PhotoImage(Image.open(file_path).resize((200,300)))	# 預覽圖片大小為200x300

previewPhoto = tkinter.Label(root, image = photo).pack()

root.mainloop()

​ 這里,由於需要不斷切換Label的image屬性,可能會遇到Python tkinter之PhotoImage圖片顯示問題

2.2.2下拉框組件

​ 下拉框組件需要使用帶ttk中的Combobox來實現,基本使用可參考:

import tkinter
from tkinter import ttk

root = tkinter.Tk()

comboBox = tkinter.ttk.Combobox(root, value = ['png','jpg'])
comboBox.current(0)	# 當前顯示第一個 
comboBox.pack()

root.mainloop()

​ 將會產生下面的效果:

2.2.3圖片文件選擇

​ 通過tkinter.filedialog中的文件選擇框組件:askopenfilename()返回打開的圖片文件的文件路徑,具體參考:

import tkinter.filedialog

file_path = tkinter.filedialog.askopenfilename(title = '選擇文件')
print(file_path)

title參數設置文件選擇框顯示時的窗體標題

2.2.4 保存文件到目標路徑

​ 通過tkinter.filedialog中的文件保存框組件:asksaveasfilename()返回保存的圖片文件的文件路徑,具體參考:

import tkinter.filedialog

file_savepath = tkinter.filedialog.asksaveasfilename(title = '保存文件',filetypes = (('JPG','.jpg'),('PNG','.png')))
print(file_savepath)

title參數設置文件選擇框顯示時的窗體標題,filetypes參數設置了保存文件時提供的文件格式下拉選項,當前設置會出現如下文件格式選項:

注意:當前只是前端頁面提供的保存頁面,實際保存文件還是在后端實現

3、組裝完成所有需求

​ 前面的分析已經夠我們組裝出我們的需求了,現在具體組裝代碼如下:

import tkinter.filedialog, tkinter.messagebox, PIL
import tkinter, os
from PIL import Image, ImageTk
from tkinter import ttk

class PFC:
    '''
        Picture Format Conversion
        圖片格式轉換器
    '''
    
    title = '圖片格式轉換器'
    quit_all = True
    filetypes = ['png','gif','jpg']
    def __init__(self, master, quit_all=None, title=None, filetypes=None):
        if title is None: title = self.title
        if quit_all is None: quit_all = self.quit_all
        if filetypes is None: filetypes = self.filetypes
        
        self.__master = master
        self.__top = tkinter.Toplevel(self.__master)
        self.__top.geometry('%dx%d'%(300,300))
        self.__top.title(title)
        self.__top.resizable(0,0)

        self.__preview_photo = ImageTk.PhotoImage(Image.new('RGB',(92,48),(255,255,255)))
        self.__source = None

        self.__default_width = tkinter.StringVar()
        self.__default_width.set('width')
        self.__default_height = tkinter.StringVar()
        self.__default_height.set('height')
        
        self.__showPhoto = tkinter.Label(self.__top, bg='white', width = 300, height = 200, image = self.__preview_photo, borderwidth = 13, text = '圖片')
        tkinter.Button(self.__top, text = '選擇文件', width = 10, bg = '#fff', command = self.__openFile).place(x = 200, y = 230)
        tkinter.Label(self.__top, text ='轉換格式:').place(y = 235)
        self.__savefiletype = ttk.Combobox(self.__top, width = 14,  value = filetypes)
        tkinter.Label(self.__top, text='轉換大小:').place(y = 270)
        self.__savefilewidth = tkinter.Entry(self.__top, width = 6, textvariable = self.__default_width)
        tkinter.Label(self.__top, text = 'X').place(x = 112, y = 270)
        self.__savefileheight = tkinter.Entry(self.__top,  width = 6, textvariable = self.__default_height)
        tkinter.Button(self.__top, text = '保存圖片', width = 10, bg = '#fff', command = self.__saveFile).place(x = 200, y = 265)

        self.__showPhoto.pack()
        self.__savefiletype.place(x = 60, y = 235)
        self.__savefilewidth.place(x = 60, y = 270)
        self.__savefileheight.place(x = 133, y = 270)
        self.__savefiletype.current(0)    
        
        self.__top.protocol('WM_DELETE_WINDOW', lambda:self.quit(flag=quit_all))

    def __getPreviewSize(self):
        return (180, int(180/self.__source.size[0]*self.__source.size[1]))

    def __openFile(self):
        filename = tkinter.filedialog.askopenfilename(title='選擇文件')
        if filename != '':
            try:
                self.__source = Image.open(filename)
            except:
                tkinter.messagebox.showerror('資源錯誤','打開文件錯誤,請確保打開圖片文件')
            else:
                self.__preview_photo =  ImageTk.PhotoImage(self.__source.resize(self.__getPreviewSize()))
                self.__showPhoto['image'] = self.__preview_photo
                self.__default_width.set(str(self.__source.size[0]))
                self.__default_height.set(str(self.__source.size[1]))

    def __saveFile(self):
        if None != self.__source:
            try:
                savesize = (int(self.__savefilewidth.get()),int(self.__savefileheight.get()))
            except:
                tkinter.messagebox.showerror('類型錯誤', '輸入中含有非數字字符')
            else:
                filetype = self.__savefiletype.get()
                savefilename = tkinter.filedialog.asksaveasfilename(title = '保存文件',filetypes=[(filetype.upper(),'.'+filetype)])
                self.__source = self.__source.resize(savesize,Image.ANTIALIAS)
                if filetype == 'jpg':
                    self.__source = self.__source.convert('RGB')
                if savefilename !='':
                    try :
                        self.__source.save(savefilename+'.'+filetype)
                    except:
                        tkinter.messagebox.showerror('保存失敗','圖片轉換失敗')
                    else:
                        tkinter.messagebox.showinfo('保存成功','圖片轉換成功')
        else:
            tkinter.messagebox.showwarning('文件為空', '請先選擇一個文件')
            
    def quit(self, flag, event=None):
        if flag:
            self.__master.quit()
        else:
            self.__top.destroy()
        
            
if __name__ == "__main__":
    root = tkinter.Tk()
    root.withdraw()
    pfc = PFC(root)
    root.mainloop()

​ 在布局上偷了點巧:完全依靠絕對定位(對tkinter布局我也不行)。運行后的效果圖如下:

​ 此工具為個人一時興起所作,個人代碼水平有限,查閱了許多資料,如有不妥望見諒。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM