最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

本文將詳細分析一款基于 wxPython 和 Pillow (PIL) 的簡單圖片處理工具,包括核心功能的實現(xià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)
        
        # 左側控制面板
        left_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # 創(chuàng)建按鈕
        select_btn = wx.Button(panel, label='選擇圖片')
        rotate_btn = wx.Button(panel, label='旋轉')
        merge_btn = wx.Button(panel, label='合并')
        compress_btn = wx.Button(panel, label='壓縮')
        
        # 創(chuàng)建列表框顯示選擇的圖片
        self.list_box = wx.ListBox(panel, size=(200, 300))
        
        # 添加組件到左側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)
        
        # 右側圖片顯示區(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)
        
        # 將左右兩側添加到主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
                
                # 計算縮放比例
                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)
                
                # 轉換為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'處理圖片時出錯: {str(e)}', '錯誤', wx.OK | wx.ICON_ERROR)
            
            # 計算縮放比例
            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)
            
            # 轉換為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):
        """當在列表中選擇圖片時觸發(fā)"""
        selection = self.list_box.GetSelection()
        if selection != wx.NOT_FOUND:
            try:
                image_path = self.selected_images[selection]
                # 使用二進制模式讀取圖片
                with Image.open(image_path) as img:
                    # 創(chuàng)建一個副本以確保圖片被完全加載
                    pil_image = img.copy()
                    self.update_image_display(pil_image)
            except Exception as e:
                wx.MessageBox(f'無法打開圖片: {str(e)}', '錯誤', 
                            wx.OK | wx.ICON_ERROR)
                
    def on_rotate(self, event):
        """旋轉當前顯示的圖片"""
        if self.current_pil_image:
            # 順時針旋轉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'旋轉圖片時出錯: {str(e)}', '錯誤', 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()

功能概述

該工具的主要功能包括:

  • 選擇圖片:從本地文件中選擇圖片并顯示在列表中。
  • 圖片預覽:點擊列表項可在右側區(qū)域預覽圖片。
  • 圖片旋轉:支持順時針旋轉當前顯示的圖片。
  • 圖片合并:將多張圖片垂直合并為一張新圖片。
  • 圖片壓縮:對合并后的圖片進行尺寸壓縮。

代碼結構與模塊解析

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

模塊說明

wx:提供圖形用戶界面支持,用于設計窗口、按鈕、列表等組件。

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

os:用于文件路徑操作。

io.BytesIO:內存中的二進制流,用于將 PIL 圖片轉換為 wx.Bitmap 顯示。

主類 ImageProcessorFrame

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

class ImageProcessorFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='圖片處理工具')
        self.selected_images = []  # 存儲已選擇的圖片路徑
        self.current_image = None  # 當前顯示的圖片(wx.Bitmap)
        self.current_pil_image = None  # 當前顯示的 PIL 圖片對象
        self.init_ui()

界面初始化

init_ui 方法負責創(chuàng)建和布局界面組件,包括按鈕、列表框和圖片顯示區(qū)域。

def init_ui(self):
    panel = wx.Panel(self)
    main_sizer = wx.BoxSizer(wx.HORIZONTAL)  # 主布局,水平分布

    # 左側控制面板
    left_sizer = wx.BoxSizer(wx.VERTICAL)
    select_btn = wx.Button(panel, label='選擇圖片')
    rotate_btn = wx.Button(panel, label='旋轉')
    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)

    # 右側圖片顯示區(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)

    # 將左右兩側添加到主布局
    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()

布局細節(jié):

  • 左側為按鈕和圖片列表框。
  • 右側為圖片顯示區(qū)域。
  • 使用 wx.BoxSizer 管理布局,保證界面響應式。

按鈕綁定:

  • on_select:選擇圖片并添加到列表。
  • on_rotate:旋轉當前圖片。
  • on_merge:合并圖片。
  • on_compress:壓縮圖片。

核心功能實現(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,并更新列表框顯示。

圖片顯示與預覽

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'處理圖片時出錯: {str(e)}', '錯誤', wx.OK | wx.ICON_ERROR)

功能:

將 PIL 圖片調整為適合顯示區(qū)域的大小。

轉換為 wx.Bitmap 后顯示在 StaticBitmap 中。

圖片旋轉

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'旋轉圖片時出錯: {str(e)}', '錯誤', wx.OK | wx.ICON_ERROR)
    else:
        wx.MessageBox('請先選擇一張圖片', '提示', wx.OK | wx.ICON_INFORMATION)

功能:

使用 Pillow.Image 的 rotate 方法實現(xià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)

功能:

  • 計算合并后圖片的總尺寸。
  • 使用 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%。

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

運行結果

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

相關文章

  • 詳解Python 中的短路評估

    詳解Python 中的短路評估

    短路是指當表達式的真值已經(jīng)確定時終止布爾運算,Python 解釋器以從左到右的方式計算表達式,這篇文章主要介紹了Python 中的短路評估,需要的朋友可以參考下
    2023-06-06
  • Django 框架模型操作入門教程

    Django 框架模型操作入門教程

    這篇文章主要介紹了Django 框架模型操作,結合實例形式分析了Django框架相關的數(shù)據(jù)庫配置、數(shù)據(jù)增刪改查等操作技巧,需要的朋友可以參考下
    2019-11-11
  • python scrapy腳本報錯問題及解決

    python scrapy腳本報錯問題及解決

    這篇文章主要介紹了python scrapy腳本報錯問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • python調用另外一個py文件中函數(shù)的具體步驟

    python調用另外一個py文件中函數(shù)的具體步驟

    這篇文章主要給大家介紹了關于python調用另外一個py文件中函數(shù)的具體步驟,要在一個Python文件中調用其他Python文件中的方法,可以使用Python的模塊導入功能,需要的朋友可以參考下
    2023-11-11
  • Php多進程實現(xiàn)代碼

    Php多進程實現(xiàn)代碼

    這篇文章主要介紹了Php多進程實現(xiàn)編程實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Python自動化辦公實戰(zhàn)案例詳解(Word、Excel、Pdf、Email郵件)

    Python自動化辦公實戰(zhàn)案例詳解(Word、Excel、Pdf、Email郵件)

    這篇文章基于Python自動化辦公,主要介紹了使用Python相關庫,依次完成Word文檔替換、Excel表格讀取、Pdf文件生成和Email自動郵件發(fā)送任務。感興趣的小伙伴可以跟隨小編一起學習一下
    2021-12-12
  • Python多個裝飾器的調用順序實例解析

    Python多個裝飾器的調用順序實例解析

    這篇文章主要介紹了Python多個裝飾器的調用順序實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05
  • Python3自動安裝第三方庫,跟pip說再見

    Python3自動安裝第三方庫,跟pip說再見

    很多朋友私信小編Python安裝第三方庫安裝技巧,在這就不一一回復大家了,今天小編給大家分享一篇教程關于Python自動安裝第三方庫的小技巧,本文以安裝plotly為例給大家詳細講解,感興趣的朋友跟隨小編一起看看吧
    2021-10-10
  • Python 從列表中取值和取索引的方法

    Python 從列表中取值和取索引的方法

    今天小編就為大家分享一篇Python 從列表中取值和取索引的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • python數(shù)據(jù)分析之公交IC卡刷卡分析

    python數(shù)據(jù)分析之公交IC卡刷卡分析

    這篇文章主要介紹了python數(shù)據(jù)分析之公交IC卡,文中有非常詳細的代碼示例,對正在學習python的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-04-04

最新評論

页游| 景东| 高雄县| 渝中区| 福安市| 嵊州市| 安徽省| 广水市| 林甸县| 大城县| 探索| 侯马市| 建昌县| 梨树县| 平原县| 如东县| 唐山市| 石渠县| 嘉善县| 怀来县| 乌兰浩特市| 阿坝县| 武胜县| 丹棱县| 三门峡市| 方正县| 金阳县| 乡宁县| 康马县| 肇州县| 天全县| 嘉义市| 内黄县| 泸西县| 山东省| 沽源县| 利津县| 丹寨县| 紫阳县| 宜黄县| 雅安市|