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

基于python制作簡單的相冊瀏覽小工具

 更新時間:2025年10月10日 09:34:26   作者:學習&實踐愛好者  
這篇文章主要為大家詳細介紹了如何基于python制作一個簡單的相冊瀏覽小工具,并且支持網(wǎng)格視圖和單圖視圖兩種視圖模式,下面小編就為大家詳細介紹一下吧

用python制作相冊瀏覽小工具

近日,歡度國慶、中秋節(jié)雙節(jié),朋友們應(yīng)拍了一些相片,故用python制作相冊瀏覽小工具試用。

依賴庫:tkinter(通常 Python 自帶)和Pillow(圖像處理庫),后者,需安裝。

安裝命令:pip install pillow

程序支持兩種視圖模式,可通過頂部控制欄的【網(wǎng)格視圖/單圖視圖】按鈕切換:

單圖視圖:默認模式,一次顯示一張圖片,支持圖片瀏覽及圖片顯示方式操作。

網(wǎng)格視圖:以縮略圖網(wǎng)格形式顯示所有圖片,便于快速查找;點擊任意縮略圖可切換到單圖視圖并顯示該圖片。

遠行效果

完整源碼

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageTk, ImageFilter
import os
import random
import math
from typing import List, Tuple, Optional, Dict

class AestheticPhotoAlbum:
    """相冊瀏覽,支持單圖查看和多圖網(wǎng)格瀏覽模式"""
    
    def __init__(self, root: tk.Tk):
        # 初始化主窗口
        self.root = root
        self.root.title("相冊瀏覽")
        self.root.geometry("1300x800")
        self.root.configure(bg="#f0f0f0")
        
        # 圖片相關(guān)變量
        self.image_files: List[str] = []
        self.current_index: int = 0
        self.original_image: Optional[Image.Image] = None
        self.processed_image: Optional[Image.Image] = None
        self.displayed_image: Optional[Image.Image] = None
        self.photo_directory: str = ""
        self.transitioning: bool = False
        self.rotation_angle: int = 0
        self.cropping: bool = False
        self.crop_start: Optional[Tuple[int, int]] = None
        self.crop_rect: Optional[int] = None
        self.thumbnail_cache: Dict[str, ImageTk.PhotoImage] = {}
        self.view_mode: str = "single"  # 視圖模式:single(單圖) 或 grid(網(wǎng)格)
        self.slideshow_running: bool = False
        
        # 布局常量
        self.grid_spacing: int = 10  # 調(diào)整間距
        self.thumb_size: Tuple[int, int] = (240,100) # 縮略圖尺寸
        self.control_padx: int = 10
        self.control_pady: int = 5
        
        # 創(chuàng)建UI組件
        self._create_widgets()
        
        # 綁定事件
        self._bind_events()
        
    def _font_config(self) -> None:
        """配置字體以支持中文顯示"""
        default_font = ('SimHei', 10)
        self.root.option_add("*Font", default_font)
        
    def _bind_events(self) -> None:
        """綁定各種事件處理"""
        # 鍵盤事件
        self.root.bind('<Left>', lambda e: self.prev_image() if self.view_mode == "single" else None)
        self.root.bind('<Right>', lambda e: self.next_image() if self.view_mode == "single" else None)
        self.root.bind('<Escape>', lambda e: self.root.quit())
        self.root.bind('<r>', lambda e: self.rotate_clockwise() if self.view_mode == "single" else None)
        self.root.bind('<R>', lambda e: self.rotate_counterclockwise() if self.view_mode == "single" else None)
        
        # 窗口大小變化事件
        self.root.bind('<Configure>', self._on_window_resize)
        
    def _create_widgets(self) -> None:
        """創(chuàng)建所有UI組件"""
        self._font_config()
        self._create_top_controls()
        self._create_display_area()
        self._create_bottom_controls()
        
    def _create_top_controls(self) -> None:
        """創(chuàng)建頂部控制欄"""
        top_frame = tk.Frame(self.root, bg="#ffffff", height=60)
        top_frame.pack(fill=tk.X, padx=10, pady=10)
        top_frame.pack_propagate(False)  # 固定高度
        
        # 選擇文件夾按鈕
        self.select_btn = tk.Button(
            top_frame, text="圖片文件夾", 
            command=self.select_directory,
            bg="#4a90e2", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2"
        )
        self.select_btn.pack(side=tk.LEFT, padx=self.control_padx)
        
        # 視圖切換按鈕
        view_frame = tk.Frame(top_frame, bg="#ffffff")
        view_frame.pack(side=tk.LEFT, padx=self.control_padx)
        
        self.view_mode_btn = tk.Button(
            view_frame, text="網(wǎng)格視圖", 
            command=self.toggle_view_mode,
            bg="#673ab7", fg="white",
            padx=self.control_padx, pady=2, 
            relief=tk.FLAT, cursor="hand2", 
            state=tk.DISABLED
        )
        self.view_mode_btn.pack(side=tk.LEFT)
        
        # 編輯工具框架
        self.edit_frame = tk.Frame(top_frame, bg="#ffffff")
        self.edit_frame.pack(side=tk.LEFT, padx=self.control_padx)
        self._create_edit_controls()
        
        # 特效按鈕
        effects_frame = tk.Frame(top_frame, bg="#ffffff")
        effects_frame.pack(side=tk.LEFT, padx=self.control_padx)
        
        self.effect_var = tk.StringVar(value="原圖")
        effects = ["原圖", "柔化", "黑白", "復古", "銳化"]
        effect_menu = tk.OptionMenu(effects_frame, self.effect_var, *effects, command=self.apply_effect)
        effect_menu.config(bg="#f8f9fa", relief=tk.FLAT)
        effect_menu.pack()
        
        # 重置按鈕
        self.reset_btn = tk.Button(
            top_frame, text="重置圖片", 
            command=self.reset_image,
            bg="#f0ad4e", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2", 
            state=tk.DISABLED
        )
        self.reset_btn.pack(side=tk.LEFT, padx=self.control_padx)

        # 使用幫助         
        self.help_btn = tk.Button(
            top_frame, text="幫助",     
            command=self.show_help,
            bg="#7f8c8d", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2"
        )
        self.help_btn.pack(side=tk.RIGHT, padx=self.control_padx)

        # 狀態(tài)標簽
        self.status_label = tk.Label(
            top_frame, text="請選擇圖片文件夾", 
            bg="#ffffff", fg="#666666"
        )
        self.status_label.pack(side=tk.RIGHT, padx=20)
        
    def _create_edit_controls(self) -> None:
        """創(chuàng)建編輯控制按鈕(旋轉(zhuǎn)、翻轉(zhuǎn))"""
        # 旋轉(zhuǎn)按鈕
        rotate_frame = tk.Frame(self.edit_frame, bg="#ffffff")
        rotate_frame.pack(side=tk.LEFT, padx=5)
        
        tk.Label(rotate_frame, text="旋轉(zhuǎn):", bg="#ffffff").pack(side=tk.TOP)
        self.rotate_cw_btn = tk.Button(
            rotate_frame, text="順時針", 
            command=self.rotate_clockwise,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.rotate_cw_btn.pack(side=tk.LEFT)
        
        self.rotate_ccw_btn = tk.Button(
            rotate_frame, text="逆時針", 
            command=self.rotate_counterclockwise,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.rotate_ccw_btn.pack(side=tk.LEFT)
        
        # 翻轉(zhuǎn)按鈕
        flip_frame = tk.Frame(self.edit_frame, bg="#ffffff")
        flip_frame.pack(side=tk.LEFT, padx=5)
        
        tk.Label(flip_frame, text="翻轉(zhuǎn):", bg="#ffffff").pack(side=tk.TOP)
        self.flip_h_btn = tk.Button(
            flip_frame, text="水平", 
            command=self.flip_horizontal,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.flip_h_btn.pack(side=tk.LEFT)
        
        self.flip_v_btn = tk.Button(
            flip_frame, text="垂直", 
            command=self.flip_vertical,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.flip_v_btn.pack(side=tk.LEFT)
       
    def _create_display_area(self) -> None:
        """創(chuàng)建圖片顯示區(qū)域(支持滾動)"""
        # 創(chuàng)建帶滾動條的容器
        self.scroll_frame = tk.Frame(self.root)
        self.scroll_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 垂直滾動條
        self.vscrollbar = ttk.Scrollbar(self.scroll_frame)
        self.vscrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 水平滾動條
        self.hscrollbar = ttk.Scrollbar(self.scroll_frame, orient=tk.HORIZONTAL)
        self.hscrollbar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 單圖模式顯示區(qū)域
        self.display_frame = tk.Frame(
            self.scroll_frame, bg="#e9ecef", 
            relief=tk.FLAT, bd=1
        )
        self.display_frame.pack(fill=tk.BOTH, expand=True)
        
        # 網(wǎng)格視圖容器
        self.grid_frame = tk.Frame(self.scroll_frame, bg="#e9ecef")
        
        # 單圖模式畫布
        self.canvas = tk.Canvas(
            self.display_frame, bg="#e9ecef", 
            highlightthickness=0, cursor="cross"
        )
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 配置滾動條
        self.canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand=self.hscrollbar.set)
        self.vscrollbar.configure(command=self.canvas.yview)
        self.hscrollbar.configure(command=self.canvas.xview)
        
    def _create_bottom_controls(self) -> None:
        """創(chuàng)建底部控制欄"""
        bottom_frame = tk.Frame(self.root, bg="#ffffff", height=60)
        bottom_frame.pack(fill=tk.X, padx=10, pady=10)
        bottom_frame.pack_propagate(False)  # 固定高度
        
        # 導航按鈕
        self.prev_btn = tk.Button(
            bottom_frame, text="上一張", 
            command=self.prev_image,
            bg="#f8f9fa", fg="#333333",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.prev_btn.pack(side=tk.LEFT, padx=20)
        
        # 圖片計數(shù)器
        self.counter_label = tk.Label(
            bottom_frame, text="0/0", 
            bg="#ffffff", fg="#333333",
            font=('SimHei', 12)
        )
        self.counter_label.pack(side=tk.LEFT, padx=20)
        
        # 下一張按鈕
        self.next_btn = tk.Button(
            bottom_frame, text="下一張", 
            command=self.next_image,
            bg="#f8f9fa", fg="#333333",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.next_btn.pack(side=tk.LEFT, padx=20)
        
        # 幻燈片播放按鈕
        self.slideshow_btn = tk.Button(
            bottom_frame, text="開始幻燈片", 
            command=self.toggle_slideshow,
            bg="#5cb85c", fg="white",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.slideshow_btn.pack(side=tk.RIGHT, padx=20)
        
    def toggle_view_mode(self) -> None:
        """切換視圖模式(單圖/網(wǎng)格)"""
        if self.view_mode == "single":
            self.view_mode = "grid"
            self.view_mode_btn.config(text="單圖視圖")
            self.display_frame.pack_forget()
            self.grid_frame.pack(fill=tk.BOTH, expand=True)
            # 強制更新布局,使 winfo_width 能獲取正確寬度
            self.grid_frame.update_idletasks()  
            self._update_grid_view()
            # 隱藏編輯工具
            self.edit_frame.pack_forget()
            self.reset_btn.pack_forget()
            # 更改鼠標樣式
            self.canvas.config(cursor="arrow")
        else:
            self.view_mode = "single"
            self.view_mode_btn.config(text="網(wǎng)格視圖")
            self.grid_frame.pack_forget()
            self.display_frame.pack(fill=tk.BOTH, expand=True)
            self._load_and_display_image()
            # 顯示編輯工具
            self.edit_frame.pack(side=tk.LEFT, padx=self.control_padx)
            self.reset_btn.pack(side=tk.LEFT, padx=self.control_padx)
        
        # 更新按鈕狀態(tài)
        self._update_button_states()
        
    def _update_grid_view(self) -> None:
        """更新網(wǎng)格視圖,顯示所有圖片縮略圖"""
        # 清空現(xiàn)有內(nèi)容
        for widget in self.grid_frame.winfo_children():
            widget.destroy()
                
        if not self.image_files:
            return
                
        # 優(yōu)先獲取網(wǎng)格容器的實際寬度(若已渲染)
        frame_width = self.grid_frame.winfo_width()
        # 若寬度為0(容器未渲染完成),則使用窗口寬度作為默認
        if frame_width == 0:
            frame_width = self.root.winfo_width() - 100  
        #cols = max(1, frame_width // (self.thumb_size[0] + self.grid_spacing))
        available_width = frame_width - 20 #將上句改為兩句, 減去容器左右邊緣的額外間距
        cols = max(1, available_width // (self.thumb_size[0] + self.grid_spacing))    
        rows = math.ceil(len(self.image_files) / cols)
        
        # 創(chuàng)建縮略圖并添加到網(wǎng)格
        for i, filename in enumerate(self.image_files):
            row = i // cols
            col = i % cols
            
            # 創(chuàng)建縮略圖容器
            thumb_frame = tk.Frame(
                self.grid_frame, 
                width=self.thumb_size[0], 
                height=self.thumb_size[1] + 30,  # 額外空間顯示文件名
                bg="#ffffff",
                relief=tk.RAISED,
                bd=1
            )
            thumb_frame.grid(
                row=row, column=col,
                padx=self.grid_spacing//2,
                pady=self.grid_spacing//2,
                sticky="nsew"
            )
            thumb_frame.grid_propagate(False)
            
            # 加載或獲取緩存的縮略圖
            try:
                if filename not in self.thumbnail_cache:
                    file_path = os.path.join(self.photo_directory, filename)
                    with Image.open(file_path) as img:
                        img.thumbnail(self.thumb_size, Image.Resampling.LANCZOS)
                        self.thumbnail_cache[filename] = ImageTk.PhotoImage(img)
                
                # 顯示縮略圖
                thumb_label = tk.Label(thumb_frame, image=self.thumbnail_cache[filename], bg="#ffffff")
                thumb_label.pack(pady=5)
                
                # 顯示文件名(簡短版本)
                short_name = filename[:15] + "..." if len(filename) > 18 else filename
                name_label = tk.Label(
                    thumb_frame, 
                    text=short_name, 
                    bg="#ffffff",
                    wraplength=self.thumb_size[0] - 10,
                    justify=tk.CENTER
                )
                name_label.pack(pady=2)
                
                # 添加點擊事件
                def on_thumb_click(index: int) -> callable:
                    def handler(event=None) -> None:
                        self.current_index = index
                        self.toggle_view_mode()
                        self._update_counter()
                    return handler
                
                thumb_frame.bind("<Button-1>", on_thumb_click(i))
                thumb_label.bind("<Button-1>", on_thumb_click(i))
                name_label.bind("<Button-1>", on_thumb_click(i))
                
                # 設(shè)置鼠標樣式為手型
                thumb_frame.config(cursor="hand2")
                thumb_label.config(cursor="hand2")
                name_label.config(cursor="hand2")
                
            except Exception as e:
                # 出錯時顯示錯誤信息而非崩潰
                error_label = tk.Label(
                    thumb_frame, 
                    text=f"無法加載\n{filename[:10]}...", 
                    bg="#ffebee",
                    fg="#b71c1c",
                    wraplength=self.thumb_size[0] - 10
                )
                error_label.pack(expand=True)
                print(f"加載縮略圖錯誤: {filename}, {str(e)}")
        
        # 配置網(wǎng)格權(quán)重
        for i in range(cols):
            self.grid_frame.grid_columnconfigure(i, weight=1)
        for i in range(rows):
            self.grid_frame.grid_rowconfigure(i, weight=1)
    
    def _on_window_resize(self, event: tk.Event) -> None:
        """窗口大小變化時的處理函數(shù)"""
        # 避免初始化時的無效調(diào)用和非主窗口事件
        if event.widget != self.root or self.transitioning:
            return
            
        # 根據(jù)當前視圖模式刷新
        if self.view_mode == "single" and self.processed_image:
            self.apply_effect(self.effect_var.get())
        elif self.view_mode == "grid" and self.image_files:
            # 延遲更新網(wǎng)格,避免頻繁觸發(fā)
            self.root.after(100, self._update_grid_view)
                
    def select_directory(self) -> None:
        """選擇圖片文件夾"""
        directory = filedialog.askdirectory(title="圖片文件夾")
        if directory:
            self.photo_directory = directory
            self._load_images()
            self.status_label.config(text=f"當前文件夾: {os.path.basename(directory)}")
            self.thumbnail_cache.clear()  # 清除緩存的縮略圖
            
    def _load_images(self) -> None:
        """加載文件夾中的圖片"""
        supported_formats = ('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.jfif', '.webp')
        self.image_files = [
            f for f in os.listdir(self.photo_directory)
            if f.lower().endswith(supported_formats)
        ]
        
        if not self.image_files:
            messagebox.showinfo("提示", "所選文件夾中沒有圖片文件")
            return
            
        # 啟用所有按鈕
        self._enable_all_controls()
        
        # 顯示第一張圖片
        self.current_index = 0
        self._update_counter()
        self._load_and_display_image()
        
    def _enable_all_controls(self) -> None:
        """啟用所有控制按鈕"""
        self.prev_btn.config(state=tk.NORMAL)
        self.next_btn.config(state=tk.NORMAL)
        self.slideshow_btn.config(state=tk.NORMAL)
        self.rotate_cw_btn.config(state=tk.NORMAL)
        self.rotate_ccw_btn.config(state=tk.NORMAL)
        self.flip_h_btn.config(state=tk.NORMAL)
        self.flip_v_btn.config(state=tk.NORMAL)
        self.reset_btn.config(state=tk.NORMAL)
        self.view_mode_btn.config(state=tk.NORMAL)
        
    def _update_button_states(self) -> None:
        """根據(jù)當前視圖模式更新按鈕狀態(tài)"""
        if self.view_mode == "grid":
            # 網(wǎng)格模式下禁用單圖操作按鈕
            self.prev_btn.config(state=tk.DISABLED)
            self.next_btn.config(state=tk.DISABLED)
            self.slideshow_btn.config(state=tk.DISABLED)
            self.rotate_cw_btn.config(state=tk.DISABLED)
            self.rotate_ccw_btn.config(state=tk.DISABLED)
            self.flip_h_btn.config(state=tk.DISABLED)
            self.flip_v_btn.config(state=tk.DISABLED)
            self.reset_btn.config(state=tk.DISABLED)
        else:
            # 單圖模式下啟用相關(guān)按鈕
            self.prev_btn.config(state=tk.NORMAL)
            self.next_btn.config(state=tk.NORMAL)
            self.slideshow_btn.config(state=tk.NORMAL)
            self.rotate_cw_btn.config(state=tk.NORMAL)
            self.rotate_ccw_btn.config(state=tk.NORMAL)
            self.flip_h_btn.config(state=tk.NORMAL)
            self.flip_v_btn.config(state=tk.NORMAL)
            self.reset_btn.config(state=tk.NORMAL)
    
    def _load_and_display_image(self) -> None:
        """加載并顯示當前圖片"""
        if not self.image_files:
            return
            
        # 獲取當前圖片路徑
        current_file = self.image_files[self.current_index]
        file_path = os.path.join(self.photo_directory, current_file)
        
        try:
            # 打開圖片,重置所有處理狀態(tài)
            self.original_image = Image.open(file_path)
            self.processed_image = self.original_image.copy()
            self.rotation_angle = 0
            self.cropping = False
            self.crop_rect = None
            
            # 應(yīng)用默認效果
            self.apply_effect(self.effect_var.get())
            
        except Exception as e:
            messagebox.showerror("錯誤", f"無法打開圖片: {str(e)}")
            # 移除無法打開的圖片
            self.image_files.pop(self.current_index)
            if not self.image_files:
                self.status_label.config(text="沒有可用的圖片文件")
                self._disable_all_controls()
                return
                
            # 調(diào)整索引
            self.current_index = min(self.current_index, len(self.image_files) - 1)
            self._update_counter()
            self._load_and_display_image()
    
    def _disable_all_controls(self) -> None:
        """禁用所有控制按鈕"""
        self.prev_btn.config(state=tk.DISABLED)
        self.next_btn.config(state=tk.DISABLED)
        self.slideshow_btn.config(state=tk.DISABLED)
        self.rotate_cw_btn.config(state=tk.DISABLED)
        self.rotate_ccw_btn.config(state=tk.DISABLED)
        self.flip_h_btn.config(state=tk.DISABLED)
        self.flip_v_btn.config(state=tk.DISABLED)
        self.reset_btn.config(state=tk.DISABLED)
        self.view_mode_btn.config(state=tk.DISABLED)
            
    def apply_effect(self, effect: str) -> None:
        """應(yīng)用圖片效果"""
        if not self.processed_image:
            return
            
        # 復制處理過的圖片以便應(yīng)用效果
        img = self.processed_image.copy()
        
        # 應(yīng)用選定的效果
        if effect == "柔化":
            img = img.filter(ImageFilter.GaussianBlur(radius=2))
        elif effect == "黑白":
            img = img.convert("L")
        elif effect == "復古":
            # 復古效果
            r, g, b = img.split()
            r = r.point(lambda i: i * 0.9)
            g = g.point(lambda i: i * 0.7)
            b = b.point(lambda i: i * 0.5)
            img = Image.merge("RGB", (r, g, b))
        elif effect == "銳化":
            img = img.filter(ImageFilter.SHARPEN)
        
        # 調(diào)整圖片大小以適應(yīng)窗口,保持比例
        self.displayed_image = self._resize_image(img)
        
        # 在畫布上顯示圖片
        self.tk_image = ImageTk.PhotoImage(image=self.displayed_image)
        self.canvas.delete("all")
        
        # 計算居中位置
        canvas_width = self.display_frame.winfo_width()
        canvas_height = self.display_frame.winfo_height()
        img_width = self.displayed_image.width
        img_height = self.displayed_image.height
        
        self.img_x = max(0, (canvas_width - img_width) // 2)
        self.img_y = max(0, (canvas_height - img_height) // 2)
        
        self.canvas.create_image(self.img_x, self.img_y, anchor=tk.NW, image=self.tk_image)
        
        # 更新狀態(tài)標簽顯示當前文件名
        current_file = self.image_files[self.current_index]
        self.status_label.config(text=f"當前圖片: {current_file}")
        
    def _resize_image(self, img: Image.Image) -> Image.Image:
        """調(diào)整圖片大小以適應(yīng)窗口,保持比例"""
        # 獲取窗口可用尺寸
        max_width = self.display_frame.winfo_width() - 40  # 留出邊距
        max_height = self.display_frame.winfo_height() - 40
        
        # 如果窗口還沒初始化,使用默認尺寸
        if max_width <= 0 or max_height <= 0:
            max_width = 1100
            max_height = 600
            
        # 計算縮放比例
        width_ratio = max_width / img.width
        height_ratio = max_height / img.height
        scale_ratio = min(width_ratio, height_ratio)
        
        # 如果圖片小于最大尺寸,則不縮放
        if scale_ratio >= 1:
            return img
            
        # 計算新尺寸
        new_width = int(img.width * scale_ratio)
        new_height = int(img.height * scale_ratio)
        
        # 調(diào)整大小,使用高質(zhì)量縮放
        return img.resize((new_width, new_height), Image.Resampling.LANCZOS)
    
    # 旋轉(zhuǎn)和翻轉(zhuǎn)功能
    def rotate_clockwise(self) -> None:
        """順時針旋轉(zhuǎn)90度"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.rotation_angle = (self.rotation_angle + 90) % 360
        self.processed_image = self.processed_image.rotate(-90, expand=True)
        self.apply_effect(self.effect_var.get())
    
    def rotate_counterclockwise(self) -> None:
        """逆時針旋轉(zhuǎn)90度"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.rotation_angle = (self.rotation_angle - 90) % 360
        self.processed_image = self.processed_image.rotate(90, expand=True)
        self.apply_effect(self.effect_var.get())
    
    def flip_horizontal(self) -> None:
        """水平翻轉(zhuǎn)圖片"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.processed_image = self.processed_image.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
        self.apply_effect(self.effect_var.get())
    
    def flip_vertical(self) -> None:
        """垂直翻轉(zhuǎn)圖片"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.processed_image = self.processed_image.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
        self.apply_effect(self.effect_var.get())
    
    
    def reset_image(self) -> None:
        """重置圖片到原始狀態(tài)"""
        if self.original_image and self.view_mode == "single":
            self.processed_image = self.original_image.copy()
            self.rotation_angle = 0
            self.cropping = False
            self.crop_rect = None
            self.canvas.config(cursor="arrow")
            self.apply_effect(self.effect_var.get())
        
    def prev_image(self) -> None:
        """顯示上一張圖片"""
        if not self.image_files or self.transitioning or self.view_mode != "single":
            return
            
        self.transitioning = True
        self.current_index = (self.current_index - 1) % len(self.image_files)
        self._update_counter()
        self._load_and_display_image()
        self.transitioning = False
        
    def next_image(self) -> None:
        """顯示下一張圖片"""
        if not self.image_files or self.transitioning or self.view_mode != "single":
            return
            
        self.transitioning = True
        self.current_index = (self.current_index + 1) % len(self.image_files)
        self._update_counter()
        self._load_and_display_image()
        self.transitioning = False
        
    def _update_counter(self) -> None:
        """更新圖片計數(shù)器"""
        self.counter_label.config(text=f"{self.current_index + 1}/{len(self.image_files)}")
        
    def toggle_slideshow(self) -> None:
        """切換幻燈片播放狀態(tài)"""
        if self.view_mode != "single":
            return
            
        if self.slideshow_running:
            self.slideshow_running = False
            self.slideshow_btn.config(text="開始幻燈片", bg="#5cb85c")
        else:
            self.slideshow_running = True
            self.slideshow_btn.config(text="停止幻燈片", bg="#d9534f")
            self._run_slideshow()
            
    def _run_slideshow(self) -> None:
        """運行幻燈片"""
        if self.slideshow_running and self.image_files and self.view_mode == "single":
            # 隨機切換效果增加美感
            effects = ["原圖", "柔化", "黑白", "復古", "銳化"]
            self.effect_var.set(random.choice(effects))
            self.next_image()
            # 3-5秒后切換到下一張
            self.root.after(random.randint(3000, 5000), self._run_slideshow)

    def show_help(self) -> None:
        """顯示使用幫助窗口"""
        # 創(chuàng)建幫助窗口
        help_window = tk.Toplevel(self.root)
        help_window.title("使用幫助")
        help_window.geometry("800x600")
        help_window.configure(bg="#f0f0f0")
        help_window.resizable(True, True)
        
        # 添加滾動條
        scrollbar = ttk.Scrollbar(help_window)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 創(chuàng)建文本區(qū)域
        help_text = tk.Text(
            help_window, 
            wrap=tk.WORD, 
            bg="#ffffff", 
            padx=20, 
            pady=20,
            font=('SimHei', 10),
            yscrollcommand=scrollbar.set
        )
        help_text.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=help_text.yview)
        
        # 幫助內(nèi)容
        help_content = """
    # 相冊瀏覽使用幫助

    ## 一、基本介紹
    這是一款圖片瀏覽與簡單編輯工具,支持單圖查看和網(wǎng)格縮略圖瀏覽兩種模式,可對圖片進行旋轉(zhuǎn)、翻轉(zhuǎn)及特效處理。


    ## 二、核心功能

    ### 1. 文件夾操作
    - 點擊頂部【圖片文件夾】按鈕,選擇存放圖片的文件夾
    - 支持格式:.jpg、.jpeg、.png、.gif、.bmp、.jfif、.webp
    - 選擇后自動加載所有圖片,默認顯示第一張


    ### 2. 視圖模式切換
    - 【網(wǎng)格視圖】:以縮略圖網(wǎng)格展示所有圖片,便于快速查找
      - 網(wǎng)格會根據(jù)窗口大小自動調(diào)整列數(shù)
      - 點擊任意縮略圖可切換到單圖模式并顯示該圖片
    - 【單圖視圖】:顯示單張高清圖片,支持圖片瀏覽及圖片顯示方式操作


    ### 3. 圖片瀏覽(單圖模式)
    - 【上一張】/【下一張】按鈕:切換圖片(支持鍵盤←/→箭頭)
    - 底部計數(shù)器:顯示當前位置(如"1/20")
    - 【開始幻燈片】:自動播放圖片,點擊按鈕可停止


    ### 4. 圖片顯示方式(單圖模式)
    - **旋轉(zhuǎn)**:
      - 【順時針】(快捷鍵r):順時針旋轉(zhuǎn)90°
      - 【逆時針】(快捷鍵R):逆時針旋轉(zhuǎn)90°
    - **翻轉(zhuǎn)**:
      - 【水平】:水平鏡像翻轉(zhuǎn)
      - 【垂直】:垂直鏡像翻轉(zhuǎn)
    - **特效**:通過下拉菜單選擇(原圖/柔化/黑白/復古/銳化)
    - **重置圖片**:恢復當前圖片到初始狀態(tài)


    ## 三、快捷鍵
     快捷鍵      功能 
     ← 左箭頭  上一張圖片 
     → 右箭頭  下一張圖片 
     Esc        退出程序 
     r          順時針旋轉(zhuǎn) 
     R          逆時針旋轉(zhuǎn) 


    ## 四、注意事項
    1. 所有編輯操作僅臨時生效,不會修改原圖文件
    2. 首次加載大量圖片時,網(wǎng)格視圖可能需要短暫加載時間
    3. 若圖片加載失敗,網(wǎng)格中會顯示"無法加載"提示
        """
        
        # 插入并格式化內(nèi)容
        help_text.insert(tk.END, help_content)
        help_text.config(state=tk.DISABLED)  # 設(shè)置為只讀
        
        # 居中顯示窗口
        help_window.update_idletasks()
        width = help_window.winfo_width()
        height = help_window.winfo_height()
        x = (self.root.winfo_width() // 2) - (width // 2) + self.root.winfo_x()
        y = (self.root.winfo_height() // 2) - (height // 2) + self.root.winfo_y()
        help_window.geometry(f"{width}x{height}+{x}+{y}")

if __name__ == "__main__":
    root = tk.Tk()
    app = AestheticPhotoAlbum(root)
    root.mainloop()

到此這篇關(guān)于基于python制作簡單的相冊瀏覽小工具的文章就介紹到這了,更多相關(guān)python相冊瀏覽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用python刪除nginx緩存文件示例(python文件操作)

    使用python刪除nginx緩存文件示例(python文件操作)

    這篇文章主要介紹了使用python刪除nginx緩存文件示例(python文件操作),需要的朋友可以參考下
    2014-03-03
  • 基于Python+smtplib實現(xiàn)郵件自動發(fā)送功能

    基于Python+smtplib實現(xiàn)郵件自動發(fā)送功能

    工作中總有各種郵件需要定期發(fā)送,手動操作不僅繁瑣還容易忘記,Python的smtplib庫完美解決這個痛點,幾行代碼就能搞定郵件自動發(fā)送,還能加上附件、HTML格式美化、定時任務(wù)等花樣玩法,所以本文介紹了基于Python+smtplib實現(xiàn)郵件自動發(fā)送功能,需要的朋友可以參考下
    2025-09-09
  • python閉包的實例詳解

    python閉包的實例詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于python閉包的實例詳解內(nèi)容,有興趣的朋友們可以學習下。
    2021-10-10
  • django 將自帶的數(shù)據(jù)庫sqlite3改成mysql實例

    django 將自帶的數(shù)據(jù)庫sqlite3改成mysql實例

    這篇文章主要介紹了django 將自帶的數(shù)據(jù)庫sqlite3改成mysql實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • 在Python中操作字典之clear()方法的使用

    在Python中操作字典之clear()方法的使用

    這篇文章主要介紹了在Python中操作字典之clear()方法的使用,是Python入門的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05
  • pydev debugger: process 10341 is connecting無法debu的解決

    pydev debugger: process 10341 is co

    這篇文章主要介紹了pydev debugger: process 10341 is connecting無法debu的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 解決keras backend 越跑越慢問題

    解決keras backend 越跑越慢問題

    這篇文章主要介紹了解決keras backend 越跑越慢問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • Python+OpenCV編寫車輛計數(shù)器系統(tǒng)

    Python+OpenCV編寫車輛計數(shù)器系統(tǒng)

    本文,我們將使用歐幾里德距離跟蹤和輪廓的概念在 Python 中使用 OpenCV 構(gòu)建車輛計數(shù)器系統(tǒng),文中的示例代碼講解詳細,感興趣的可以了解一下
    2022-05-05
  • Python?OpenCV獲取圖片的基本參數(shù)信息

    Python?OpenCV獲取圖片的基本參數(shù)信息

    在圖像處理領(lǐng)域,了解圖像的基本信息是必不可少的第一步,本文主要介紹了如何使用Python?OpenCV獲取圖片的基本參數(shù)信息,感興趣的小伙伴可以了解下
    2024-11-11
  • python實現(xiàn)超市掃碼儀計費

    python實現(xiàn)超市掃碼儀計費

    這篇文章主要為大家詳細介紹了python實現(xiàn)超市掃碼儀計費,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05

最新評論

东乡族自治县| 潢川县| 康马县| 木里| 萝北县| 卓尼县| 肥城市| 五大连池市| 锡林浩特市| 河曲县| 徐汇区| 台东市| 浏阳市| 正安县| 高密市| 大同市| 天峻县| 来宾市| 孝义市| 彭阳县| 白玉县| 阿巴嘎旗| 佳木斯市| 安平县| 雷波县| 托克托县| 乌什县| 巴林右旗| 东兴市| 郁南县| 比如县| 扶余县| 高安市| 浏阳市| 霍林郭勒市| 新乡市| 景德镇市| 尉犁县| 宿迁市| 库伦旗| 宁强县|