Python 实现图片轮播及音乐循环播放

Python 实现图片轮播及音乐循环播放

本项目实现的功能(简易的音乐电子相册):

  • 每 5s 自动播放下一张图片
  • 可以手动点击,播放下一张图片
  • 循环播放 MP3 音乐文件

使用说明

需将文件夹 photomusic 以及最终执行的 album.exe 文件放到同一目录下,双击运行 album.exe 即可。

  • 注意至少在 photo 文件夹下包含一张图片才能正常运行 album.exe
  • music 文件夹存放所要循环播放的 MP3 文件,如果不需要播放音乐,也可直接删除 music 文件夹
  • 这里没有实现获取 photo 目录下的子目录的图片。主要考虑到照片太多的话,每次自动播放都从第一张图片开始,后面的图片可能需要很久才能播放,这可能不太友好

项目目录结构

(eln35) C:\Users\eln\PycharmProjects\Album>tree
文件夹 PATH 列表
卷序列号为 209A-F77C
C:.
│  album.exe    # 最终生成的 exe 文件,从 dist 文件夹中复制出来
│  album.py     # 源代码
│  README.html  # 从 README.md 生成的网页
│  README.md    # 说明文档
├─.idea        # PyCharm 中新建项目时自动生成的文件夹,用于存放项目的配置信息。其中包括版本控制信息、历史记录等等
│  └─inspectionProfiles
├─build        # 生成 exe 文件时自动生成的
│  └─album
├─dist         # 生成 exe 文件时自动生成的,最终的生成 exe 文件保存在这里
├─music        # 测试用的音乐文件(没有该路径也不影响运行)
│      Kalimba.mp3
│      Maid with the Flaxen Hair.mp3
│      Sleep Away.mp3
│
├─photo        # 测试用的图片(必须包含一张图片)
│      Chrysanthemum.jpg
│      Desert.jpg
│      Hydrangeas.jpg
│      Jellyfish.jpg
│      Koala.jpg
│      Lighthouse.jpg
│      Penguins.jpg
│      Tulips.jpg
│
└─__pycache__   # python 运行的缓存文件夹,自动生成

生成 exe 文件

安装 python 的 pyinstaller 库:

(eln35) C:\Users\eln\PycharmProjects\Album>pip install pyinstaller

生成 exe 文件:

(eln35) C:\Users\eln\PycharmProjects\Album>rmdir /s /q dist
(eln35) C:\Users\eln\PycharmProjects\Album>rmdir /s /q build

(eln35) C:\Users\eln\PycharmProjects\Album>pyinstaller -F -w album.py
  • -w 直接发布的 exe 应用带命令行调试窗口,在指令内加入 -w 命令可以屏蔽
  • -F 注意指令区分大小写。这里是大写。使用 -F 指令可以把应用打包成一个独立的 exe 文件,否则是一个带各种 dll 和依赖文件的文件夹
  • -p 这个指令后面可以增加 pyinstaller 搜索模块的路径。因为应用打包涉及的模块很多。这里可以自己添加路径。不过经过笔者测试, site-packages 目录下都是可以被识别的,不需要再手动添加

源代码

# -*- coding: utf-8 -*-

"""
Created on 2019/8/20

@author: eln

@requirements: PyCharm 2017.2; Python 3.5.6 |Anaconda 4.1.1 (64-bit)

@decription: 用 Python 制作一个电子相册
"""
# pip install pillow pygame mutagen
import os
import sys
import threading
import tkinter as tk
import time
from PIL import ImageTk, Image
import pygame
from mutagen.mp3 import MP3


def playmusic():
    """播放音乐。"""
    Path = r'music\\'
    try:
        list1 = os.listdir(Path)  # 获取指定路径下所有的 mp3 文件
        for x in list1:
            if not (x.endswith('.mp3')):
                list1.remove(x)

        list2 = []
        for i in list1:
            s = os.path.join(Path, i)  # 对路径与文件进行拼接
            list2.append(s)

        while True:
            for n in list2:
                # 获取每一首歌的时长
                path = n
                audio = MP3(n)
                pygame.mixer.init()  # 初始化所有引入的模块
                pygame.mixer.music.load(path)  # 载入音乐,音乐可以是 ogg、mp3 等格式
                pygame.mixer.music.play()  # 播放载入的音乐
                time.sleep(int(audio.info.length))  # 获取每一首歌曲的时长,使程序存活的时长等于歌曲时长

    except Exception as e:
        print("Exception: %s" % e)


resolution = (1366, 768)  # 分辨率
Path = r'photo\\'  # 相册路径
Interval = 5  # 播放间隔.单位:s
Index = 0  # 当前照片计数
title = "电子相册"  # 窗口标题


def getfiles():
    """获取图片文件名。"""
    files = os.listdir(Path)
    for x in files:
        if not (x.endswith('.jpg') or x.endswith('.JPG') or x.endswith('.png')):
            files.remove(x)
    return files


files = getfiles()
print(files)
scaler = Image.ANTIALIAS  # 设定 ANTIALIAS ,即抗锯齿
root = tk.Tk()  # 创建窗口
root.title(title)  # 设置窗口标题

img_in = Image.open(Path + files[0])  # 加载第一张图片
# img_in = Image.open("load.jpg")  # 加载第一张图片
w, h = img_in.size  # 获取图片大小
size_new = (int(w * resolution[1] / h), resolution[1])
img_out = img_in.resize(size_new, scaler)  # 重新设置大小
img = ImageTk.PhotoImage(img_out)  # 用 PhotoImage 打开图片
panel = tk.Label(root, image=img)  # Label 自适应图片大小
panel.pack(side="bottom", fill="both", expand="yes")


def callback(e):
    """手动切换图片。"""
    try:
        global Index

        for i, x in enumerate(files):
            # 判断文件是否存在
            if not os.path.isfile(Path + '%s' % x):
                break

            if i != Index:  # 跳过已播放的图片
                continue

            print('手动处理图片', x, Index)  # python 3.5
            # print(unicode('手动处理图片 %s %d' % (x, Index), "utf8", errors="ignore"))  # python 2.7.15
            img_in = Image.open(Path + '%s' % x)
            print(img_in)
            w, h = img_in.size
            size_new = (int(w * resolution[1] / h), resolution[1])
            img_out = img_in.resize(size_new, scaler)
            img2 = ImageTk.PhotoImage(img_out)
            panel.configure(image=img2)
            panel.image = img2
            Index += 1
            if Index >= len(files):
                Index = 0
            break

    except Exception as e:
        print("Exception: %s " % e)
        sys.exit(1)


# root.bind("<Return>", callback)
root.bind("<Button-1>", callback)  # 点击窗口切换下一张图片


def image_change():
    """自动切换图片。"""
    try:
        global Index

        time.sleep(3)
        while True:
            for i, x in enumerate(files):
                # 判断文件是否存在
                if not os.path.isfile(Path + '%s' % x):
                    break

                if i != Index:  # 跳过已播放的图片
                    continue

                print('自动处理图片', x, Index)  # python 3.5
                # print(unicode('自动处理图片 %s %d' % (x, Index), "utf8", errors="ignore"))  # python 2.7.15
                img_in = Image.open(Path + '%s' % x)
                w, h = img_in.size
                size_new = (int(w * resolution[1] / h), resolution[1])
                img_out = img_in.resize(size_new, scaler)
                img2 = ImageTk.PhotoImage(img_out)
                panel.configure(image=img2)
                panel.image = img2
                Index += 1
                if Index >= len(files):
                    Index = 0
                time.sleep(Interval)

    except Exception as e:
        print("Exception: %s " % e)
        sys.exit(1)


m = threading.Thread(target=playmusic)  # 创建音乐播放线程
t = threading.Thread(target=image_change)  # 创建图片切换线程
# python 可以通过 threading module 来创建新的线程,然而在创建线程的线程(父线程)关闭之后,相应的子线程可能却没有关闭
# 需要把 setDaemon 函数放在 start 函数前面解决此问题
m.setDaemon(True)
m.start()  # 启动线程
t.start()  # 启动线程
root.mainloop()  # 窗口循环
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值