使用Python實(shí)現(xiàn)圖片處理工具
本文將詳細(xì)分析一款基于 wxPython 和 Pillow (PIL) 的簡單圖片處理工具,包括核心功能的實(shí)現(xiàn)與代碼的設(shè)計(jì)思路。這款工具支持圖片選擇、旋轉(zhuǎn)、合并、壓縮,并且具有友好的圖形用戶界面(GUI)。
全部代碼
import wx
from PIL import Image
import os
from io import BytesIO
class ImageProcessorFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='圖片處理工具')
self.selected_images = []
self.current_image = None
self.current_pil_image = None # 存儲PIL Image對象
self.init_ui()
def init_ui(self):
panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
# 左側(cè)控制面板
left_sizer = wx.BoxSizer(wx.VERTICAL)
# 創(chuàng)建按鈕
select_btn = wx.Button(panel, label='選擇圖片')
rotate_btn = wx.Button(panel, label='旋轉(zhuǎn)')
merge_btn = wx.Button(panel, label='合并')
compress_btn = wx.Button(panel, label='壓縮')
# 創(chuàng)建列表框顯示選擇的圖片
self.list_box = wx.ListBox(panel, size=(200, 300))
# 添加組件到左側(cè)sizer
left_sizer.Add(select_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(self.list_box, 1, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(rotate_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(merge_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(compress_btn, 0, wx.ALL | wx.EXPAND, 5)
# 右側(cè)圖片顯示區(qū)域
right_sizer = wx.BoxSizer(wx.VERTICAL)
self.image_display = wx.StaticBitmap(panel, size=(600, 400))
right_sizer.Add(self.image_display, 1, wx.EXPAND | wx.ALL, 5)
# 將左右兩側(cè)添加到主sizer
main_sizer.Add(left_sizer, 0, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(right_sizer, 1, wx.EXPAND | wx.ALL, 5)
# 綁定事件
select_btn.Bind(wx.EVT_BUTTON, self.on_select)
rotate_btn.Bind(wx.EVT_BUTTON, self.on_rotate)
merge_btn.Bind(wx.EVT_BUTTON, self.on_merge)
compress_btn.Bind(wx.EVT_BUTTON, self.on_compress)
self.list_box.Bind(wx.EVT_LISTBOX, self.on_select_image)
panel.SetSizer(main_sizer)
self.SetSize((900, 600))
self.Centre()
def update_image_display(self, pil_image):
"""更新圖片顯示"""
if pil_image:
try:
# 確保圖片是RGB模式
if pil_image.mode != 'RGB':
pil_image = pil_image.convert('RGB')
# 獲取顯示區(qū)域的大小
display_size = self.image_display.GetSize()
image_size = pil_image.size
# 計(jì)算縮放比例
ratio = min(display_size[0]/image_size[0],
display_size[1]/image_size[1])
new_size = (int(image_size[0] * ratio),
int(image_size[1] * ratio))
# 調(diào)整圖片大小
resized_image = pil_image.resize(new_size, Image.Resampling.LANCZOS)
# 轉(zhuǎn)換為wx.Bitmap
image_buffer = BytesIO()
resized_image.save(image_buffer, format='PNG')
image_buffer.seek(0) # 重置緩沖區(qū)指針到開始位置
wx_image = wx.Image(image_buffer, type=wx.BITMAP_TYPE_PNG)
wx_bitmap = wx_image.ConvertToBitmap()
# 更新顯示
self.image_display.SetBitmap(wx_bitmap)
self.current_image = wx_bitmap
self.current_pil_image = pil_image
# 刷新顯示
self.image_display.Refresh()
except Exception as e:
wx.MessageBox(f'處理圖片時(shí)出錯(cuò): {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
# 計(jì)算縮放比例
ratio = min(display_size[0]/image_size[0],
display_size[1]/image_size[1])
new_size = (int(image_size[0] * ratio),
int(image_size[1] * ratio))
# 調(diào)整圖片大小
resized_image = pil_image.resize(new_size, Image.Resampling.LANCZOS)
# 轉(zhuǎn)換為wx.Bitmap
image_buffer = BytesIO()
resized_image.save(image_buffer, format='PNG')
image_buffer.seek(0) # 重置緩沖區(qū)指針到開始位置
wx_image = wx.Image(image_buffer, type=wx.BITMAP_TYPE_PNG)
wx_bitmap = wx_image.ConvertToBitmap()
# 更新顯示
self.image_display.SetBitmap(wx_bitmap)
self.current_image = wx_bitmap
self.current_pil_image = pil_image
# 刷新顯示
self.image_display.Refresh()
def on_select(self, event):
with wx.FileDialog(self, "選擇圖片文件", wildcard="圖片文件 (*.jpg;*.png)|*.jpg;*.png",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
paths = fileDialog.GetPaths()
self.selected_images.extend(paths)
self.list_box.Set([os.path.basename(path) for path in self.selected_images])
def on_select_image(self, event):
"""當(dāng)在列表中選擇圖片時(shí)觸發(fā)"""
selection = self.list_box.GetSelection()
if selection != wx.NOT_FOUND:
try:
image_path = self.selected_images[selection]
# 使用二進(jìn)制模式讀取圖片
with Image.open(image_path) as img:
# 創(chuàng)建一個(gè)副本以確保圖片被完全加載
pil_image = img.copy()
self.update_image_display(pil_image)
except Exception as e:
wx.MessageBox(f'無法打開圖片: {str(e)}', '錯(cuò)誤',
wx.OK | wx.ICON_ERROR)
def on_rotate(self, event):
"""旋轉(zhuǎn)當(dāng)前顯示的圖片"""
if self.current_pil_image:
# 順時(shí)針旋轉(zhuǎn)90度
try:
rotated_image = self.current_pil_image.rotate(-90, expand=True)
self.update_image_display(rotated_image)
except Exception as e:
wx.MessageBox(f'旋轉(zhuǎn)圖片時(shí)出錯(cuò): {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
else:
wx.MessageBox('請先選擇一張圖片', '提示',
wx.OK | wx.ICON_INFORMATION)
def on_merge(self, event):
if len(self.selected_images) < 2:
wx.MessageBox('請至少選擇兩張圖片', '提示',
wx.OK | wx.ICON_INFORMATION)
return
max_width = 0
total_height = 0
images = []
for img_path in self.selected_images:
img = Image.open(img_path)
max_width = max(max_width, img.width)
total_height += img.height
images.append(img)
merged_image = Image.new('RGB', (max_width, total_height))
current_height = 0
for img in images:
if img.width < max_width:
x_offset = (max_width - img.width) // 2
else:
x_offset = 0
merged_image.paste(img, (x_offset, current_height))
current_height += img.height
save_path = os.path.join(os.path.dirname(self.selected_images[0]),
'merged.jpg')
merged_image.save(save_path)
wx.MessageBox(f'圖片已合并保存至: {save_path}', '成功',
wx.OK | wx.ICON_INFORMATION)
def on_compress(self, event):
merged_path = os.path.join(os.path.dirname(self.selected_images[0]),
'merged.jpg')
if not os.path.exists(merged_path):
wx.MessageBox('請先合并圖片', '提示', wx.OK | wx.ICON_INFORMATION)
return
img = Image.open(merged_path)
width = int(img.width * 0.5)
height = int(img.height * 0.5)
compressed_img = img.resize((width, height), Image.Resampling.LANCZOS)
save_path = os.path.join(os.path.dirname(merged_path), 'compressed.jpg')
compressed_img.save(save_path, quality=85, optimize=True)
wx.MessageBox(f'壓縮后的圖片已保存至: {save_path}', '成功',
wx.OK | wx.ICON_INFORMATION)
def main():
app = wx.App()
frame = ImageProcessorFrame()
frame.Show()
app.MainLoop()
if __name__ == '__main__':
main()
功能概述
該工具的主要功能包括:
- 選擇圖片:從本地文件中選擇圖片并顯示在列表中。
- 圖片預(yù)覽:點(diǎn)擊列表項(xiàng)可在右側(cè)區(qū)域預(yù)覽圖片。
- 圖片旋轉(zhuǎn):支持順時(shí)針旋轉(zhuǎn)當(dāng)前顯示的圖片。
- 圖片合并:將多張圖片垂直合并為一張新圖片。
- 圖片壓縮:對合并后的圖片進(jìn)行尺寸壓縮。
代碼結(jié)構(gòu)與模塊解析
import wx from PIL import Image import os from io import BytesIO
模塊說明
wx:提供圖形用戶界面支持,用于設(shè)計(jì)窗口、按鈕、列表等組件。
Pillow (PIL):Python圖像處理庫,支持加載、旋轉(zhuǎn)、縮放、保存圖片等功能。
os:用于文件路徑操作。
io.BytesIO:內(nèi)存中的二進(jìn)制流,用于將 PIL 圖片轉(zhuǎn)換為 wx.Bitmap 顯示。
主類 ImageProcessorFrame
ImageProcessorFrame 繼承自 wx.Frame,是程序的主窗口,負(fù)責(zé)布局、事件綁定和功能處理。
class ImageProcessorFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None, title='圖片處理工具')
self.selected_images = [] # 存儲已選擇的圖片路徑
self.current_image = None # 當(dāng)前顯示的圖片(wx.Bitmap)
self.current_pil_image = None # 當(dāng)前顯示的 PIL 圖片對象
self.init_ui()
界面初始化
init_ui 方法負(fù)責(zé)創(chuàng)建和布局界面組件,包括按鈕、列表框和圖片顯示區(qū)域。
def init_ui(self):
panel = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.HORIZONTAL) # 主布局,水平分布
# 左側(cè)控制面板
left_sizer = wx.BoxSizer(wx.VERTICAL)
select_btn = wx.Button(panel, label='選擇圖片')
rotate_btn = wx.Button(panel, label='旋轉(zhuǎn)')
merge_btn = wx.Button(panel, label='合并')
compress_btn = wx.Button(panel, label='壓縮')
self.list_box = wx.ListBox(panel, size=(200, 300))
left_sizer.Add(select_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(self.list_box, 1, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(rotate_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(merge_btn, 0, wx.ALL | wx.EXPAND, 5)
left_sizer.Add(compress_btn, 0, wx.ALL | wx.EXPAND, 5)
# 右側(cè)圖片顯示區(qū)域
right_sizer = wx.BoxSizer(wx.VERTICAL)
self.image_display = wx.StaticBitmap(panel, size=(600, 400))
right_sizer.Add(self.image_display, 1, wx.EXPAND | wx.ALL, 5)
# 將左右兩側(cè)添加到主布局
main_sizer.Add(left_sizer, 0, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(right_sizer, 1, wx.EXPAND | wx.ALL, 5)
# 綁定按鈕事件
select_btn.Bind(wx.EVT_BUTTON, self.on_select)
rotate_btn.Bind(wx.EVT_BUTTON, self.on_rotate)
merge_btn.Bind(wx.EVT_BUTTON, self.on_merge)
compress_btn.Bind(wx.EVT_BUTTON, self.on_compress)
self.list_box.Bind(wx.EVT_LISTBOX, self.on_select_image)
panel.SetSizer(main_sizer)
self.SetSize((900, 600))
self.Centre()
布局細(xì)節(jié):
- 左側(cè)為按鈕和圖片列表框。
- 右側(cè)為圖片顯示區(qū)域。
- 使用 wx.BoxSizer 管理布局,保證界面響應(yīng)式。
按鈕綁定:
- on_select:選擇圖片并添加到列表。
- on_rotate:旋轉(zhuǎn)當(dāng)前圖片。
- on_merge:合并圖片。
- on_compress:壓縮圖片。
核心功能實(shí)現(xiàn)
圖片選擇
def on_select(self, event):
with wx.FileDialog(self, "選擇圖片文件", wildcard="圖片文件 (*.jpg;*.png)|*.jpg;*.png",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.FD_MULTIPLE) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
paths = fileDialog.GetPaths() # 獲取選擇的文件路徑
self.selected_images.extend(paths) # 添加到已選擇列表
self.list_box.Set([os.path.basename(path) for path in self.selected_images]) # 顯示文件名
功能:
打開文件對話框,支持多選。
將選擇的圖片路徑存儲到 self.selected_images,并更新列表框顯示。
圖片顯示與預(yù)覽
def update_image_display(self, pil_image):
if pil_image:
try:
if pil_image.mode != 'RGB':
pil_image = pil_image.convert('RGB')
display_size = self.image_display.GetSize()
image_size = pil_image.size
ratio = min(display_size[0]/image_size[0], display_size[1]/image_size[1])
new_size = (int(image_size[0] * ratio), int(image_size[1] * ratio))
resized_image = pil_image.resize(new_size, Image.Resampling.LANCZOS)
image_buffer = BytesIO()
resized_image.save(image_buffer, format='PNG')
wx_image = wx.Image(image_buffer, type=wx.BITMAP_TYPE_PNG)
wx_bitmap = wx_image.ConvertToBitmap()
self.image_display.SetBitmap(wx_bitmap)
self.current_image = wx_bitmap
self.current_pil_image = pil_image
self.image_display.Refresh()
except Exception as e:
wx.MessageBox(f'處理圖片時(shí)出錯(cuò): {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
功能:
將 PIL 圖片調(diào)整為適合顯示區(qū)域的大小。
轉(zhuǎn)換為 wx.Bitmap 后顯示在 StaticBitmap 中。
圖片旋轉(zhuǎn)
def on_rotate(self, event):
if self.current_pil_image:
try:
rotated_image = self.current_pil_image.rotate(-90, expand=True)
self.update_image_display(rotated_image)
except Exception as e:
wx.MessageBox(f'旋轉(zhuǎn)圖片時(shí)出錯(cuò): {str(e)}', '錯(cuò)誤', wx.OK | wx.ICON_ERROR)
else:
wx.MessageBox('請先選擇一張圖片', '提示', wx.OK | wx.ICON_INFORMATION)
功能:
使用 Pillow.Image 的 rotate 方法實(shí)現(xiàn)順時(shí)針旋轉(zhuǎn)。
圖片合并
def on_merge(self, event):
if len(self.selected_images) < 2:
wx.MessageBox('請至少選擇兩張圖片', '提示', wx.OK | wx.ICON_INFORMATION)
return
max_width = 0
total_height = 0
images = []
for img_path in self.selected_images:
img = Image.open(img_path)
max_width = max(max_width, img.width)
total_height += img.height
images.append(img)
merged_image = Image.new('RGB', (max_width, total_height))
current_height = 0
for img in images:
x_offset = (max_width - img.width) // 2
merged_image.paste(img, (x_offset, current_height))
current_height += img.height
save_path = os.path.join(os.path.dirname(self.selected_images[0]), 'merged.jpg')
merged_image.save(save_path)
wx.MessageBox(f'圖片已合并保存至: {save_path}', '成功', wx.OK | wx.ICON_INFORMATION)
功能:
- 計(jì)算合并后圖片的總尺寸。
- 使用 Image.new 創(chuàng)建空白圖片。
- 將每張圖片逐一粘貼。
圖片壓縮
def on_compress(self, event):
merged_path = os.path.join(os.path.dirname(self.selected_images[0]), 'merged.jpg')
if not os.path.exists(merged_path):
wx.MessageBox('請先合并圖片', '提示', wx.OK | wx.ICON_INFORMATION)
return
img = Image.open(merged_path)
width = int(img.width * 0.5)
height = int(img.height * 0.5)
compressed_img = img.resize((width, height), Image.Resampling.LANCZOS)
save_path = os.path.join(os.path.dirname(merged_path), 'compressed.jpg')
compressed_img.save(save_path, quality=85, optimize=True)
wx.MessageBox(f'壓縮后的圖片已保存至: {save_path}', '成功', wx.OK | wx.ICON_INFORMATION)
功能:
將合并后的圖片尺寸縮小為原來的 50%。
設(shè)置壓縮質(zhì)量為 85%,并保存優(yōu)化后的圖片。
運(yùn)行結(jié)果

到此這篇關(guān)于使用Python實(shí)現(xiàn)圖片處理工具的文章就介紹到這了,更多相關(guān)Python圖片處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用random模塊實(shí)現(xiàn)擲骰子游戲的示例代碼
這篇文章主要介紹了Python使用random模塊實(shí)現(xiàn)擲骰子游戲的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
Python Vaex實(shí)現(xiàn)快速分析100G大數(shù)據(jù)量
Vaex是一個(gè)開源的DataFrame庫,它可以對表格數(shù)據(jù)集進(jìn)行可視化、探索、分析,甚至機(jī)器學(xué)習(xí),這些數(shù)據(jù)集和你的硬盤驅(qū)動(dòng)器一樣大。本文就來聊聊如何利用Vaex實(shí)現(xiàn)快速分析100G大數(shù)據(jù)量,需要的可以參考一下2023-03-03
python人工智能tensorflow函數(shù)np.random模塊使用
這篇文章主要為大家介紹了python人工智能tensorflow函數(shù)np.random模塊使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
python教程之用py2exe將PY文件轉(zhuǎn)成EXE文件
py2exe是一個(gè)將python腳本轉(zhuǎn)換成windows上的可獨(dú)立執(zhí)行的可執(zhí)行程序(*.exe)的工具,這樣,你就可以不用裝python而在windows系統(tǒng)上運(yùn)行這個(gè)可執(zhí)行程序。2014-06-06
Python使用grequests(gevent+requests)并發(fā)發(fā)送請求過程解析
這篇文章主要介紹了Python使用grequests并發(fā)發(fā)送請求過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09

