173 lines
7.2 KiB
Python
173 lines
7.2 KiB
Python
import tkinter as tk
|
|
from tkinter import Canvas
|
|
import ttkbootstrap as ttk
|
|
from PIL import Image, ImageTk, ImageDraw
|
|
import math
|
|
|
|
class DVDAnimation:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("DVD插入动画")
|
|
|
|
# 设置窗口大小和居中
|
|
window_width = 800
|
|
window_height = 600
|
|
screen_width = root.winfo_screenwidth()
|
|
screen_height = root.winfo_screenheight()
|
|
x = (screen_width - window_width) // 2
|
|
y = (screen_height - window_height) // 2
|
|
self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
|
|
|
|
# 创建画布
|
|
self.canvas = Canvas(root, width=window_width, height=window_height, bg='black')
|
|
self.canvas.pack()
|
|
|
|
# 图片尺寸
|
|
self.dvd_player_width = 400
|
|
self.dvd_player_height = 300
|
|
self.dvd_width = 200
|
|
self.dvd_height = 200
|
|
self.icon_width = 100
|
|
self.icon_height = 100
|
|
self.icon_cer_width = 200
|
|
self.icon_cer_height = 200
|
|
|
|
|
|
# 位置参数
|
|
self.dvd_player_x = (window_width - self.dvd_player_width) // 2
|
|
self.dvd_player_y = (window_height - self.dvd_player_height) // 2
|
|
|
|
# 加载图片
|
|
self.load_images()
|
|
|
|
# 动画参数
|
|
self.animation_steps = 50
|
|
self.current_step = 0
|
|
self.dvd_start_x = window_width
|
|
self.dvd_end_x = self.dvd_player_x + self.dvd_player_width // 2 - self.dvd_width // 2
|
|
|
|
# 开始动画
|
|
self.animate()
|
|
|
|
def load_images(self):
|
|
"""加载图片"""
|
|
try:
|
|
# 加载您的图片
|
|
self.dvd_player_img = Image.open('1.png').resize((self.dvd_player_width, self.dvd_player_height), Image.Resampling.LANCZOS)
|
|
self.dvd_img = Image.open('2.png').resize((self.dvd_width, self.dvd_height), Image.Resampling.LANCZOS)
|
|
self.icon_img = Image.open('3.png').resize((self.icon_width, self.icon_height), Image.Resampling.LANCZOS)
|
|
self.icon_cer_img = Image.open('2.5.png').resize((self.icon_cer_width, self.icon_cer_height), Image.Resampling.LANCZOS)
|
|
except FileNotFoundError:
|
|
print("请将您的图片命名为1.png、2.png、3.png并放在同一目录下")
|
|
self.root.destroy()
|
|
return
|
|
|
|
# 转换为Tkinter可用的格式
|
|
self.dvd_player_photo = ImageTk.PhotoImage(self.dvd_player_img)
|
|
self.dvd_photo = ImageTk.PhotoImage(self.dvd_img)
|
|
self.icon_photo = ImageTk.PhotoImage(self.icon_img)
|
|
self.icon_cer_photo = ImageTk.PhotoImage(self.icon_cer_img)
|
|
|
|
|
|
# 创建叠加后的DVD图片
|
|
self.create_combined_dvd_image()
|
|
|
|
def create_combined_dvd_image(self):
|
|
"""创建DVD和ICON叠加的图片,保持透明度"""
|
|
# 创建一个临时画布来叠加图片
|
|
combined = Image.new('RGBA', (self.dvd_width, self.dvd_height), (0, 0, 0, 0))
|
|
|
|
# 先放置DVD
|
|
combined.paste(self.dvd_img, (0, 0), self.dvd_img)
|
|
|
|
# 计算ICON的位置(居中)
|
|
icon_x = (self.dvd_width - self.icon_width) // 2 + 60
|
|
icon_y = (self.dvd_height - self.icon_height) // 2
|
|
|
|
# 处理ICON的透明度,使其与DVD的透明区域匹配
|
|
for x in range(self.icon_width):
|
|
for y in range(self.icon_height):
|
|
dvd_x = icon_x + x
|
|
dvd_y = icon_y + y
|
|
|
|
if 0 <= dvd_x < self.dvd_width and 0 <= dvd_y < self.dvd_height:
|
|
# 获取DVD对应位置的alpha值
|
|
dvd_alpha = self.dvd_img.getpixel((dvd_x, dvd_y))[3]
|
|
|
|
if dvd_alpha > 0: # 只在DVD不透明的区域绘制ICON
|
|
icon_pixel = self.icon_img.getpixel((x, y))
|
|
if icon_pixel[3] > 0: # ICON也不透明
|
|
# 混合颜色
|
|
alpha_ratio = icon_pixel[3] / 255.0
|
|
new_r = int(icon_pixel[0] * alpha_ratio)
|
|
new_g = int(icon_pixel[1] * alpha_ratio)
|
|
new_b = int(icon_pixel[2] * alpha_ratio)
|
|
new_a = min(dvd_alpha, icon_pixel[3])
|
|
combined.putpixel((dvd_x, dvd_y), (new_r, new_g, new_b, new_a))
|
|
|
|
|
|
|
|
# 计算ICON的位置(居中)
|
|
icon_x = (self.dvd_width - self.icon_cer_width) // 2
|
|
icon_y = (self.dvd_height - self.icon_cer_height) // 2
|
|
|
|
# 处理ICON的透明度,使其与DVD的透明区域匹配
|
|
for x in range(self.icon_cer_width):
|
|
for y in range(self.icon_cer_height):
|
|
dvd_x = icon_x + x
|
|
dvd_y = icon_y + y
|
|
|
|
if 0 <= dvd_x < self.dvd_width and 0 <= dvd_y < self.dvd_height:
|
|
# 获取DVD对应位置的alpha值
|
|
dvd_alpha = self.dvd_img.getpixel((dvd_x, dvd_y))[3]
|
|
|
|
if dvd_alpha > 0: # 只在DVD不透明的区域绘制ICON
|
|
icon_pixel = self.icon_cer_img.getpixel((x, y))
|
|
if icon_pixel[3] > 0: # ICON也不透明
|
|
# 混合颜色
|
|
alpha_ratio = icon_pixel[3] / 255.0
|
|
new_r = int(icon_pixel[0] * alpha_ratio)
|
|
new_g = int(icon_pixel[1] * alpha_ratio)
|
|
new_b = int(icon_pixel[2] * alpha_ratio)
|
|
new_a = min(dvd_alpha, icon_pixel[3])
|
|
combined.putpixel((dvd_x, dvd_y), (new_r, new_g, new_b, new_a))
|
|
|
|
self.combined_dvd_photo = ImageTk.PhotoImage(combined)
|
|
|
|
def animate(self):
|
|
"""执行动画"""
|
|
if self.current_step <= self.animation_steps:
|
|
# 清除画布
|
|
self.canvas.delete("all")
|
|
|
|
# 计算当前DVD位置
|
|
progress = self.current_step / self.animation_steps
|
|
# 使用缓动函数使动画更平滑
|
|
eased_progress = 1 - (1 - progress) ** 3
|
|
current_x = self.dvd_start_x - (self.dvd_start_x - self.dvd_end_x) * eased_progress
|
|
|
|
# DVD的Y位置(插入一半的效果)
|
|
dvd_y = self.dvd_player_y + self.dvd_player_height // 2 - self.dvd_height // 2
|
|
|
|
# 绘制DVD机(最高图层)
|
|
self.canvas.create_image(self.dvd_player_x, self.dvd_player_y,
|
|
anchor=tk.NW, image=self.dvd_player_photo)
|
|
|
|
# 绘制组合的DVD图片
|
|
self.canvas.create_image(current_x, dvd_y,
|
|
anchor=tk.NW, image=self.combined_dvd_photo)
|
|
|
|
# 更新动画步骤
|
|
self.current_step += 1
|
|
|
|
# 继续动画
|
|
self.root.after(30, self.animate)
|
|
|
|
|
|
def main():
|
|
root = ttk.Window(themename="darkly")
|
|
app = DVDAnimation(root)
|
|
root.mainloop()
|
|
|
|
if __name__ == "__main__":
|
|
main() |