亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用Python實(shí)現(xiàn)圖片處理工具

 更新時(shí)間:2025年01月10日 09:27:56   作者:winfredzhang  
這篇文章主要介紹了如何基于?wxPython?和?Pillow?(PIL)?的簡(jiǎn)單圖片處理工具,可以支持圖片選擇,旋轉(zhuǎn),合并和壓縮等功能,感興趣的小伙伴可以了解下

本文將詳細(xì)分析一款基于 wxPython 和 Pillow (PIL) 的簡(jiǎn)單圖片處理工具,包括核心功能的實(shí)現(xiàn)與代碼的設(shè)計(jì)思路。這款工具支持圖片選擇、旋轉(zhuǎn)、合并、壓縮,并且具有友好的圖形用戶(hù)界面(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  # 存儲(chǔ)PIL Image對(duì)象
        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ū)指針到開(kāi)始位置
                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ū)指針到開(kāi)始位置
            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'無(wú)法打開(kāi)圖片: {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('請(qǐng)先選擇一張圖片', '提示', 
                         wx.OK | wx.ICON_INFORMATION)
            
    def on_merge(self, event):
        if len(self.selected_images) < 2:
            wx.MessageBox('請(qǐng)至少選擇兩張圖片', '提示', 
                         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('請(qǐng)先合并圖片', '提示', 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)前顯示的圖片。
  • 圖片合并:將多張圖片垂直合并為一張新圖片。
  • 圖片壓縮:對(duì)合并后的圖片進(jìn)行尺寸壓縮。

代碼結(jié)構(gòu)與模塊解析

import wx
from PIL import Image
import os
from io import BytesIO

模塊說(shuō)明

wx:提供圖形用戶(hù)界面支持,用于設(shè)計(jì)窗口、按鈕、列表等組件。

Pillow (PIL):Python圖像處理庫(kù),支持加載、旋轉(zhuǎn)、縮放、保存圖片等功能。

os:用于文件路徑操作。

io.BytesIO:內(nèi)存中的二進(jìn)制流,用于將 PIL 圖片轉(zhuǎn)換為 wx.Bitmap 顯示。

主類(lèi) ImageProcessorFrame

ImageProcessorFrame 繼承自 wx.Frame,是程序的主窗口,負(fù)責(zé)布局、事件綁定和功能處理。

class ImageProcessorFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='圖片處理工具')
        self.selected_images = []  # 存儲(chǔ)已選擇的圖片路徑
        self.current_image = None  # 當(dāng)前顯示的圖片(wx.Bitmap)
        self.current_pil_image = None  # 當(dāng)前顯示的 PIL 圖片對(duì)象
        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])  # 顯示文件名

功能:

打開(kāi)文件對(duì)話框,支持多選。

將選擇的圖片路徑存儲(chǔ)到 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('請(qǐng)先選擇一張圖片', '提示', 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('請(qǐng)至少選擇兩張圖片', '提示', 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('請(qǐng)先合并圖片', '提示', 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)

功能:

將合并后的圖片尺寸縮小為原來(lái)的 50%。

設(shè)置壓縮質(zhì)量為 85%,并保存優(yōu)化后的圖片。

運(yùn)行結(jié)果

到此這篇關(guān)于使用Python實(shí)現(xiàn)圖片處理工具的文章就介紹到這了,更多相關(guān)Python圖片處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python使用random模塊實(shí)現(xiàn)擲骰子游戲的示例代碼

    Python使用random模塊實(shí)現(xiàn)擲骰子游戲的示例代碼

    這篇文章主要介紹了Python使用random模塊實(shí)現(xiàn)擲骰子游戲的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Python Vaex實(shí)現(xiàn)快速分析100G大數(shù)據(jù)量

    Python Vaex實(shí)現(xiàn)快速分析100G大數(shù)據(jù)量

    Vaex是一個(gè)開(kāi)源的DataFrame庫(kù),它可以對(duì)表格數(shù)據(jù)集進(jìn)行可視化、探索、分析,甚至機(jī)器學(xué)習(xí),這些數(shù)據(jù)集和你的硬盤(pán)驅(qū)動(dòng)器一樣大。本文就來(lái)聊聊如何利用Vaex實(shí)現(xiàn)快速分析100G大數(shù)據(jù)量,需要的可以參考一下
    2023-03-03
  • python人工智能tensorflow函數(shù)np.random模塊使用

    python人工智能tensorflow函數(shù)np.random模塊使用

    這篇文章主要為大家介紹了python人工智能tensorflow函數(shù)np.random模塊使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Python基礎(chǔ)知識(shí)之變量的詳解

    Python基礎(chǔ)知識(shí)之變量的詳解

    這篇文章主要介紹了Python基礎(chǔ)知識(shí)之變量的詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-04-04
  • Python中的異常處理學(xué)習(xí)筆記

    Python中的異常處理學(xué)習(xí)筆記

    這篇文章主要介紹了Python中的異常處理學(xué)習(xí)筆記,本文講解了常見(jiàn)的異常類(lèi)、自定義異常類(lèi)、捕獲異常、拋出異常、上下文管理器等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • python 如何比較字符串是否一樣

    python 如何比較字符串是否一樣

    這篇文章主要介紹了python 如何比較字符串是否一樣的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Python代碼調(diào)試技巧教程詳解

    Python代碼調(diào)試技巧教程詳解

    這篇文章主要為大家介紹了Python代碼的一些方便快捷的調(diào)試技巧,文中含有詳細(xì)新的步驟操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-10-10
  • python教程之用py2exe將PY文件轉(zhuǎn)成EXE文件

    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
  • Windows 64位下python3安裝nltk模塊

    Windows 64位下python3安裝nltk模塊

    這篇文章主要為大家詳細(xì)介紹了Windows 64位下python3安裝nltk模塊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Python使用grequests(gevent+requests)并發(fā)發(fā)送請(qǐng)求過(guò)程解析

    Python使用grequests(gevent+requests)并發(fā)發(fā)送請(qǐng)求過(guò)程解析

    這篇文章主要介紹了Python使用grequests并發(fā)發(fā)送請(qǐng)求過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09

最新評(píng)論