AbiuAbia 2025-04-13 18:00 采纳率: 0%
浏览 4

type object 'PsDImage' has no attribute 'load

再导入PSD后点击嵌入水印一直显示操作失败:type object 'PsDImage' has no attribute 'load这个问题应该怎么修改哇,真的不懂啊

import os
import datetime
import tkinter as tk
from tkinter import filedialog, messagebox
from psd_tools import PSDImage
from xml.etree import ElementTree as ET

class LegacyPSDWatermarkApp:
    def __init__(self, root):
        self.root = root
        root.title("PSD暗标工具 v1.5 (最终修正版)")
        root.geometry("620x420")
        
        # 修正后的XMP命名空间配置
        self.XMP_NS = {
            'xap': 'http://ns.adobe.com/xap/1.0/',
            'mark': 'http://192.168.31.165/watermark/1.0/'  # ← 修正后的正确域名格式
        }
        
        self.create_widgets()
    
    def create_widgets(self):
        """创建界面组件"""
        # 文件选择区
        file_frame = tk.Frame(self.root, padx=10, pady=10)
        file_frame.pack(fill=tk.X)
        self.btn_open = tk.Button(file_frame, text="打开PSD", command=self.select_file, 
                                bg="#37474F", fg="white", width=10)
        self.btn_open.pack(side=tk.LEFT)
        self.file_path = tk.StringVar()
        self.entry_path = tk.Entry(file_frame, textvariable=self.file_path, width=50)
        self.entry_path.pack(side=tk.LEFT, padx=10)

        # 水印操作区
        action_frame = tk.Frame(self.root, pady=15)
        action_frame.pack()
        self.qq_entry = tk.Entry(action_frame, width=20, font=('Arial', 12))
        self.qq_entry.pack(side=tk.LEFT, padx=5)
        self.btn_add = tk.Button(action_frame, text="添加水印", command=self.add_watermark,
                                bg="#00695C", fg="white", width=10)
        self.btn_add.pack(side=tk.LEFT, padx=5)
        self.btn_check = tk.Button(action_frame, text="检测水印", command=self.check_watermark,
                                  bg="#BF360C", fg="white", width=10)
        self.btn_check.pack(side=tk.LEFT, padx=5)

        # 日志显示区
        self.log = tk.Text(self.root, height=12, state=tk.DISABLED, wrap=tk.WORD,
                          font=('Consolas', 9), bg="#263238", fg="#ECEFF1")
        self.log.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    # ----------------- 核心功能修正 -----------------
    def add_watermark(self):
        """添加水印(兼容旧版API)"""
        qq = self.qq_entry.get().strip()
        psd_path = self.file_path.get()
        
        if not self._validate(qq, psd_path):
            return
        
        try:
            self._log(f"🚀 开始处理: {os.path.basename(psd_path)}")
            
            # === 关键修正:使用正确的加载方式 ===
            with open(psd_path, 'rb') as f:
                psd = PSDImage.load(f)  # 旧版正确加载方式
                
            # 生成XMP数据
            xmp_data = self._generate_xmp(qq)
            self._log("✅ XMP元数据生成成功")
            
            # 更新资源数据
            self._update_xmp_resource(psd, xmp_data)
            
            # 保存文件
            new_path = self._get_save_path(psd_path)
            with open(new_path, 'wb') as f:
                psd.save(f)  # 旧版正确保存方式
            
            self._log(f"💾 文件保存成功: {os.path.basename(new_path)}")
            messagebox.showinfo("成功", "水印添加完成!")
        except Exception as e:
            self._show_error(f"❌ 操作失败:{str(e)}")

    def check_watermark(self):
        """检测水印(兼容旧版API)"""
        psd_path = self.file_path.get()
        if not os.path.exists(psd_path):
            self._show_error("文件不存在")
            return
        
        try:
            self._log(f"🔍 正在检测: {os.path.basename(psd_path)}")
            with open(psd_path, 'rb') as f:
                psd = PSDImage.load(f)  # 旧版加载方式
                
            qq = self._extract_watermark(psd)
            
            if qq:
                self.qq_entry.delete(0, tk.END)
                self.qq_entry.insert(0, qq)
                self._log(f"🕵️ 检测到水印: {qq}")
                messagebox.showinfo("结果", f"找到水印: {qq}")
            else:
                self._log("⚠️ 未检测到水印")
                messagebox.showinfo("结果", "未找到水印")
        except Exception as e:
            self._show_error(f"❌ 检测失败: {str(e)}")

    def _update_xmp_resource(self, psd, xmp_data):
        """更新XMP资源(兼容旧版方法)"""
        # 查找XMP资源(资源ID 1033)
        xmp_res_list = [res for res in psd.resources if res.resource_id == 1033]
        
        if xmp_res_list:
            # 更新现有资源
            xmp_res_list[0].data = xmp_data
            self._log("🔄 更新现有XMP资源")
        else:
            # 创建新资源(关键步骤)
            from psd_tools.psd import Resource
            new_res = Resource()
            new_res.resource_id = 1033  # 官方XMP资源ID
            new_res.name = "XMP Data"
            new_res.data = xmp_data
            psd.resources.append(new_res)
            self._log("✨ 新建XMP资源")

    # ----------------- 辅助方法修正 -----------------
    def _generate_xmp(self, qq):
        """生成符合规范的XMP数据"""
        root = ET.Element('{http://ns.adobe.com/xap/1.0/}xmpmeta', {
            'xmlns:xap': self.XMP_NS['xap'],
            'xmlns:mark': self.XMP_NS['mark']  # 使用修正后的域名
        })
        desc = ET.SubElement(root, '{http://ns.adobe.com/xap/1.0/}Description')
        watermark = ET.SubElement(desc, '{http://192.168.31.165/watermark/1.0/}watermark')
        ET.SubElement(watermark, 'qq').text = qq
        ET.SubElement(watermark, 'timestamp').text = datetime.datetime.now().isoformat()
        
        return ET.tostring(root, encoding='utf-8', xml_declaration=True)

    def _extract_watermark(self, psd):
        """从资源块提取水印"""
        try:
            xmp_res_list = [res for res in psd.resources if res.resource_id == 1033]
            if not xmp_res_list:
                return None
                
            root = ET.fromstring(xmp_res_list[0].data)
            return root.findtext('.//{http://192.168.31.165/watermark/1.0/}qq')  # 域名保持一致
        except Exception as e:
            self._log(f"⚠️ 解析错误: {str(e)}")
            return None

    # ----------------- 其他方法保持不变 -----------------
    def _validate(self, qq, path):
        """输入验证"""
        errors = []
        if not qq.isdigit() or len(qq) <5:
            errors.append("水印必须为5位以上数字")
        if not path.lower().endswith('.psd'):
            errors.append("请选择PSD格式文件")
        if not os.path.exists(path):
            errors.append("文件不存在")
        
        if errors:
            self._show_error("\n".join(errors))
            return False
        return True

    def _get_save_path(self, original):
        """生成防重复文件名"""
        base, ext = os.path.splitext(original)
        counter = 1
        while True:
            new_path = f"{base}_安全版{counter}{ext}"
            if not os.path.exists(new_path):
                return new_path
            counter += 1

    def select_file(self):
        """选择文件"""
        filename = filedialog.askopenfilename(
            filetypes=[("PSD文件", "*.psd"), ("所有文件", "*.*")]
        )
        if filename:
            self.file_path.set(filename)
            self._log(f"📂 已选择文件: {os.path.basename(filename)}")

    def _log(self, message):
        """日志记录"""
        self.log.config(state=tk.NORMAL)
        self.log.insert(tk.END, f"[{datetime.datetime.now().strftime('%H:%M:%S')}] {message}\n")
        self.log.config(state=tk.DISABLED)
        self.log.see(tk.END)

    def _show_error(self, msg):
        """显示错误"""
        messagebox.showerror("错误", msg)
        self._log(f"❌ {msg}")

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

  • 写回答

3条回答 默认 最新

  • 码农阿豪@新空间 新星创作者: 前端开发技术领域 2025-04-13 18:01
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    问题分析: 在导入PSD文件后点击嵌入水印时,出现了操作失败的错误提示,显示"attribute error: type object 'PSDImage' has no attribute 'load"。这表明在该代码中,PSDImage对象没有load属性,导致了操作失败。 解决方法: 要修复这个问题,需要使用正确的方法加载PSDImage对象。根据代码中的信息,我们可以看到在add_watermark方法中,PSDImage对象被加载时使用了错误的方式,应该使用正确的方法。 正确的加载方式是使用psd_tools.psd.PSDImage.open来加载PSD文件,而不是PSDImage.load。下面是修正后的代码片段:
    # ----------------- 核心功能修正 -----------------
    def add_watermark(self):
        """添加水印(兼容旧版API)"""
        qq = self.qq_entry.get().strip()
        psd_path = self.file_path.get()
        if not self._validate(qq, psd_path):
            return
        try:
            self._log(f"🚀 开始处理: {os.path.basename(psd_path)}")
            # 关键修正:使用正确的加载方式
            with open(psd_path, 'rb') as f:
                psd = PSDImage.open(f)  # 修改为正确的加载方式
            # 生成XMP数据
            xmp_data = self._generate_xmp(qq)
            self._log("✅ XMP元数据生成成功")
            # 更新资源数据
            self._update_xmp_resource(psd, xmp_data)
            # 保存文件
            new_path = self._get_save_path(psd_path)
            with open(new_path, 'wb') as f:
                psd.save(f)  # 修改为正确的保存方式
            self._log(f"💾 文件保存成功")
    

    通过修改加载PSDImage对象的方式为PSDImage.open,应该能够解决该问题。在修复后重新运行代码,应该可以成功地嵌入水印并保存PSD文件。

    评论

报告相同问题?

问题事件

  • 创建了问题 4月13日