8b46fb30 by 柴进

清理无用代码

1 parent e554cf55
...@@ -1889,69 +1889,25 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -1889,69 +1889,25 @@ class ImageGeneratorWindow(QMainWindow):
1889 QMessageBox.warning(self, "警告", "没有找到有效的图片文件") 1889 QMessageBox.warning(self, "警告", "没有找到有效的图片文件")
1890 1890
1891 def add_clipboard_image(self, image): 1891 def add_clipboard_image(self, image):
1892 """添加剪贴板图像(用于拖拽和粘贴功能)""" 1892 """添加剪贴板图像(用于拖拽图像数据)"""
1893 try: 1893 try:
1894 self.logger.info("开始处理剪贴板图像")
1895 # 生成临时文件名
1896 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") 1894 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
1897 temp_dir = Path(tempfile.gettempdir()) / "nano_banana_app" 1895 temp_dir = Path(tempfile.gettempdir()) / "nano_banana_app"
1898 temp_dir.mkdir(exist_ok=True) 1896 temp_dir.mkdir(exist_ok=True)
1899 self.logger.info(f"临时目录: {temp_dir}") 1897 temp_file_path = temp_dir / f"clipboard_{timestamp}.png"
1900 1898
1901 # 统一使用PNG格式保存,确保跨平台兼容 1899 normalized = image.convertToFormat(QImage.Format.Format_ARGB32)
1902 file_extension = ".png" 1900 success = normalized.save(str(temp_file_path), "PNG")
1903 temp_file_path = temp_dir / f"clipboard_{timestamp}{file_extension}"
1904
1905 # 尝试多种保存方式,确保兼容性
1906 self.logger.info(f"QImage信息: {image.width()}x{image.height()}, format={image.format()}, isNull={image.isNull()}")
1907 success = False
1908
1909 # 方法1: 先转换为 RGB32 格式再保存(避免格式不兼容导致保存异常)
1910 try:
1911 normalized = image.convertToFormat(QImage.Format.Format_ARGB32)
1912 success = normalized.save(str(temp_file_path), "PNG")
1913 self.logger.info(f"方法1(ARGB32转换)保存结果: {success}")
1914 except Exception as e:
1915 self.logger.warning(f"方法1保存失败: {e}")
1916
1917 # 方法2: 直接保存原始格式
1918 if not success:
1919 try:
1920 success = image.save(str(temp_file_path), "PNG")
1921 self.logger.info(f"方法2(原始格式)保存结果: {success}")
1922 except Exception as e:
1923 self.logger.warning(f"方法2保存失败: {e}")
1924
1925 # 方法3: 通过 QPixmap 中转保存
1926 if not success: 1901 if not success:
1927 try: 1902 success = image.save(str(temp_file_path), "PNG")
1928 pixmap = QPixmap.fromImage(image)
1929 success = pixmap.save(str(temp_file_path), "PNG")
1930 self.logger.info(f"方法3(QPixmap中转)保存结果: {success}")
1931 except Exception as e:
1932 self.logger.warning(f"方法3保存失败: {e}")
1933 1903
1934 # 验证保存的文件确实可被加载为缩略图 1904 if success and temp_file_path.exists() and temp_file_path.stat().st_size > 0:
1935 if success and temp_file_path.exists():
1936 file_size = temp_file_path.stat().st_size
1937 self.logger.info(f"保存文件大小: {file_size} bytes")
1938 if file_size == 0:
1939 self.logger.error("保存的文件为空(0字节)")
1940 success = False
1941
1942 if success and temp_file_path.exists():
1943 self.uploaded_images.append(str(temp_file_path)) 1905 self.uploaded_images.append(str(temp_file_path))
1906 self.update_image_preview()
1944 self.image_count_label.setText(f"已选择 {len(self.uploaded_images)} 张") 1907 self.image_count_label.setText(f"已选择 {len(self.uploaded_images)} 张")
1945 self.status_label.setText("● 已添加剪贴板图片") 1908 self.status_label.setText("● 已添加剪贴板图片")
1946 self.status_label.setStyleSheet("QLabel { color: #34C759; }") 1909 self.status_label.setStyleSheet("QLabel { color: #34C759; }")
1947 self.logger.info(f"剪贴板图片已成功保存到: {temp_file_path}")
1948 # 延迟到下一个事件循环刷新预览,避免 macOS 剪贴板上下文阻塞 UI 更新
1949 QTimer.singleShot(0, self.update_image_preview)
1950
1951 # 检查极速模式下的多图限制
1952 # self.check_multi_image_mode_conflict()
1953 else: 1910 else:
1954 self.logger.error("图片保存失败")
1955 QMessageBox.critical(self, "错误", "无法保存剪贴板图片") 1911 QMessageBox.critical(self, "错误", "无法保存剪贴板图片")
1956 1912
1957 except Exception as e: 1913 except Exception as e:
...@@ -1959,42 +1915,34 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -1959,42 +1915,34 @@ class ImageGeneratorWindow(QMainWindow):
1959 QMessageBox.critical(self, "错误", f"添加剪贴板图片失败: {str(e)}") 1915 QMessageBox.critical(self, "错误", f"添加剪贴板图片失败: {str(e)}")
1960 1916
1961 def _safe_get_clipboard_image(self): 1917 def _safe_get_clipboard_image(self):
1962 """安全地从剪贴板获取图像,兼容 macOS 高低版本""" 1918 """安全地从剪贴板获取纯图像数据(如截图),兼容 macOS 高低版本
1919
1920 注意:Finder 复制的文件应通过 paste_from_clipboard 中的 hasUrls 分支处理,
1921 不会走到这里。此方法只处理纯图像数据(截图、从应用复制的图片等)。
1922 """
1963 clipboard = QApplication.clipboard() 1923 clipboard = QApplication.clipboard()
1964 1924
1965 # 方法1: 从 MIME data 的 image formats 读取原始字节构造 QImage 1925 # 方法1: 从 MIME data 读取图像
1966 # 避免直接调用 clipboard.image(),该方法在 macOS 26 可能导致 native crash 1926 # 避免直接调用 clipboard.image(),该方法在 macOS 26 可能导致 native crash
1967 try: 1927 try:
1968 mime_data = clipboard.mimeData() 1928 mime_data = clipboard.mimeData()
1969 if mime_data is None: 1929 if mime_data is not None:
1970 self.logger.warning("clipboard.mimeData() 返回 None") 1930 # 尝试从图像 MIME 格式读取原始字节
1971 else: 1931 for mime_type in ("image/png", "image/jpeg", "image/bmp", "image/tiff", "application/x-qt-image"):
1972 formats = list(mime_data.formats()) 1932 if mime_type in mime_data.formats():
1973 self.logger.info(f"剪贴板MIME类型: {formats}")
1974
1975 # 尝试从常见图像 MIME 格式读取字节数据
1976 image_mime_types = [
1977 "image/png", "image/jpeg", "image/bmp", "image/tiff",
1978 "application/x-qt-image",
1979 ]
1980 for mime_type in image_mime_types:
1981 if mime_type in formats:
1982 raw_data = mime_data.data(mime_type) 1933 raw_data = mime_data.data(mime_type)
1983 if raw_data and len(raw_data) > 0: 1934 if raw_data and len(raw_data) > 0:
1984 image = QImage() 1935 image = QImage()
1985 if image.loadFromData(raw_data): 1936 if image.loadFromData(raw_data):
1986 self.logger.info(f"方法1成功: 从 {mime_type} 构造图像 {image.width()}x{image.height()}")
1987 return image 1937 return image
1988 1938
1989 # 尝试 hasImage + imageData(比 clipboard.image() 更安全) 1939 # 尝试 hasImage + imageData
1990 if mime_data.hasImage(): 1940 if mime_data.hasImage():
1991 image_data = mime_data.imageData() 1941 image_data = mime_data.imageData()
1992 if image_data is not None: 1942 if isinstance(image_data, QImage) and not image_data.isNull():
1993 if isinstance(image_data, QImage) and not image_data.isNull(): 1943 return image_data
1994 self.logger.info(f"方法1b成功: imageData() {image_data.width()}x{image_data.height()}")
1995 return image_data
1996 except Exception as e: 1944 except Exception as e:
1997 self.logger.warning(f"方法1 (MIME data) 失败: {e}") 1945 self.logger.warning(f"MIME data 方式获取剪贴板图像失败: {e}")
1998 1946
1999 # 方法2: macOS 专用 - 用 osascript 将剪贴板图片写入临时文件 1947 # 方法2: macOS 专用 - 用 osascript 将剪贴板图片写入临时文件
2000 if platform.system() == "Darwin": 1948 if platform.system() == "Darwin":
...@@ -2002,7 +1950,6 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2002,7 +1950,6 @@ class ImageGeneratorWindow(QMainWindow):
2002 import subprocess 1950 import subprocess
2003 temp_path = Path(tempfile.gettempdir()) / "nano_banana_app" / "_clipboard_tmp.png" 1951 temp_path = Path(tempfile.gettempdir()) / "nano_banana_app" / "_clipboard_tmp.png"
2004 temp_path.parent.mkdir(exist_ok=True) 1952 temp_path.parent.mkdir(exist_ok=True)
2005 # 删除旧文件
2006 if temp_path.exists(): 1953 if temp_path.exists():
2007 temp_path.unlink() 1954 temp_path.unlink()
2008 1955
...@@ -2020,48 +1967,38 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2020,48 +1967,38 @@ class ImageGeneratorWindow(QMainWindow):
2020 ' error "no image"\n' 1967 ' error "no image"\n'
2021 'end try\n' 1968 'end try\n'
2022 ) 1969 )
2023 result = subprocess.run( 1970 result = subprocess.run(["osascript", "-e", script], capture_output=True, timeout=5)
2024 ["osascript", "-e", script],
2025 capture_output=True, timeout=5
2026 )
2027 if result.returncode == 0 and temp_path.exists() and temp_path.stat().st_size > 0: 1971 if result.returncode == 0 and temp_path.exists() and temp_path.stat().st_size > 0:
2028 image = QImage(str(temp_path)) 1972 image = QImage(str(temp_path))
2029 if not image.isNull(): 1973 if not image.isNull():
2030 self.logger.info(f"方法2成功: osascript 读取剪贴板 {image.width()}x{image.height()}")
2031 return image 1974 return image
2032 except Exception as e: 1975 except Exception as e:
2033 self.logger.warning(f"方法2 (osascript) 失败: {e}") 1976 self.logger.warning(f"osascript 方式获取剪贴板图像失败: {e}")
2034 1977
2035 # 方法3: 最后手段 - 直接调用 clipboard.image()(低版本 macOS 可靠 1978 # 方法3: 直接调用 clipboard.image()(低版本 macOS / Windows / Linux
2036 try: 1979 try:
2037 image = clipboard.image() 1980 image = clipboard.image()
2038 if image and not image.isNull(): 1981 if image and not image.isNull():
2039 self.logger.info(f"方法3成功: clipboard.image() {image.width()}x{image.height()}")
2040 return image 1982 return image
2041 except Exception as e: 1983 except Exception as e:
2042 self.logger.warning(f"方法3 (clipboard.image) 失败: {e}") 1984 self.logger.warning(f"clipboard.image() 失败: {e}")
2043 1985
2044 return None 1986 return None
2045 1987
2046 def paste_from_clipboard(self): 1988 def paste_from_clipboard(self):
2047 """从剪贴板粘贴图像""" 1989 """从剪贴板粘贴图像"""
2048 try: 1990 try:
2049 self.logger.info("开始粘贴剪贴板图片")
2050 clipboard = QApplication.clipboard() 1991 clipboard = QApplication.clipboard()
2051 mime_data = clipboard.mimeData() 1992 mime_data = clipboard.mimeData()
2052 1993
2053 # 优先处理文件URL(如 Finder 中复制的图片文件) 1994 # 优先处理文件URL(如 Finder / 资源管理器中复制的图片文件)
2054 if mime_data and mime_data.hasUrls(): 1995 if mime_data and mime_data.hasUrls():
2055 image_files = [] 1996 valid_ext = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'}
2056 for url in mime_data.urls(): 1997 image_files = [
2057 if url.isLocalFile(): 1998 url.toLocalFile() for url in mime_data.urls()
2058 file_path = url.toLocalFile() 1999 if url.isLocalFile() and Path(url.toLocalFile()).suffix.lower() in valid_ext
2059 self.logger.info(f"剪贴板包含文件: {file_path}") 2000 ]
2060 if Path(file_path).suffix.lower() in {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'}:
2061 image_files.append(file_path)
2062
2063 if image_files: 2001 if image_files:
2064 self.logger.info(f"从剪贴板文件URL添加 {len(image_files)} 张图片")
2065 added = 0 2002 added = 0
2066 for fp in image_files: 2003 for fp in image_files:
2067 if self.validate_image_file(fp): 2004 if self.validate_image_file(fp):
...@@ -2074,16 +2011,12 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2074,16 +2011,12 @@ class ImageGeneratorWindow(QMainWindow):
2074 self.status_label.setStyleSheet("QLabel { color: #34C759; }") 2011 self.status_label.setStyleSheet("QLabel { color: #34C759; }")
2075 return 2012 return
2076 2013
2077 # 没有文件URL,尝试获取剪贴板中的图像数据(如截图、从应用复制的图片 2014 # 没有文件URL,尝试获取纯图像数据(截图、从应用复制的图片等
2078 image = self._safe_get_clipboard_image() 2015 image = self._safe_get_clipboard_image()
2079
2080 if image is None: 2016 if image is None:
2081 self.logger.warning("剪贴板中没有可用的图像")
2082 QMessageBox.information(self, "信息", "剪贴板中没有图片,请先复制一张图片") 2017 QMessageBox.information(self, "信息", "剪贴板中没有图片,请先复制一张图片")
2083 return 2018 return
2084 2019
2085 self.logger.info(f"成功获取剪贴板图像数据: {image.width()}x{image.height()}")
2086
2087 # 保存到临时文件 2020 # 保存到临时文件
2088 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f") 2021 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
2089 temp_dir = Path(tempfile.gettempdir()) / "nano_banana_app" 2022 temp_dir = Path(tempfile.gettempdir()) / "nano_banana_app"
...@@ -2093,11 +2026,9 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2093,11 +2026,9 @@ class ImageGeneratorWindow(QMainWindow):
2093 normalized = image.convertToFormat(QImage.Format.Format_ARGB32) 2026 normalized = image.convertToFormat(QImage.Format.Format_ARGB32)
2094 if not normalized.save(temp_file_path, "PNG"): 2027 if not normalized.save(temp_file_path, "PNG"):
2095 if not image.save(temp_file_path, "PNG"): 2028 if not image.save(temp_file_path, "PNG"):
2096 self.logger.error("剪贴板图片保存失败")
2097 QMessageBox.critical(self, "错误", "无法保存剪贴板图片") 2029 QMessageBox.critical(self, "错误", "无法保存剪贴板图片")
2098 return 2030 return
2099 2031
2100 self.logger.info(f"剪贴板图片已保存: {temp_file_path}")
2101 self.uploaded_images.append(temp_file_path) 2032 self.uploaded_images.append(temp_file_path)
2102 self.update_image_preview() 2033 self.update_image_preview()
2103 self.image_count_label.setText(f"已选择 {len(self.uploaded_images)} 张") 2034 self.image_count_label.setText(f"已选择 {len(self.uploaded_images)} 张")
...@@ -2105,7 +2036,7 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2105,7 +2036,7 @@ class ImageGeneratorWindow(QMainWindow):
2105 self.status_label.setStyleSheet("QLabel { color: #34C759; }") 2036 self.status_label.setStyleSheet("QLabel { color: #34C759; }")
2106 2037
2107 except Exception as e: 2038 except Exception as e:
2108 self.logger.error(f"粘贴剪贴板图片时发生错误: {str(e)}", exc_info=True) 2039 self.logger.error(f"粘贴失败: {e}", exc_info=True)
2109 QMessageBox.critical(self, "错误", f"粘贴失败: {str(e)}") 2040 QMessageBox.critical(self, "错误", f"粘贴失败: {str(e)}")
2110 2041
2111 def validate_image_file(self, file_path: str) -> bool: 2042 def validate_image_file(self, file_path: str) -> bool:
...@@ -2153,53 +2084,31 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2153,53 +2084,31 @@ class ImageGeneratorWindow(QMainWindow):
2153 2084
2154 def keyPressEvent(self, event): 2085 def keyPressEvent(self, event):
2155 """处理键盘事件""" 2086 """处理键盘事件"""
2156 # 检测键盘组合键 2087 # Ctrl+V / Cmd+V 粘贴
2157 key_text = event.text() 2088 if event.key() == Qt.Key_V and event.modifiers() in (Qt.ControlModifier, Qt.MetaModifier):
2158 key_int = event.key()
2159 modifiers = event.modifiers()
2160 self.logger.info(f"键盘事件: key={key_int}, text='{key_text}', modifiers={modifiers}")
2161
2162 # Ctrl+V 粘贴
2163 if event.key() == Qt.Key_V and event.modifiers() == Qt.ControlModifier:
2164 self.logger.info("检测到 Ctrl+V 粘贴组合键")
2165 self.paste_from_clipboard() 2089 self.paste_from_clipboard()
2166 event.accept() 2090 event.accept()
2167 return 2091 return
2168 2092
2169 # Cmd+V 粘贴 (macOS)
2170 elif event.key() == Qt.Key_V and event.modifiers() == Qt.MetaModifier:
2171 self.logger.info("检测到 Cmd+V 粘贴组合键 (macOS)")
2172 self.paste_from_clipboard()
2173 event.accept()
2174 return
2175
2176 self.logger.debug(f"未处理的键盘事件: {key_text}")
2177 super().keyPressEvent(event) 2093 super().keyPressEvent(event)
2178 2094
2179 def update_image_preview(self): 2095 def update_image_preview(self):
2180 """Update image preview thumbnails""" 2096 """Update image preview thumbnails"""
2181 self.logger.info(f"更新图片预览,共 {len(self.uploaded_images)} 张图片")
2182 try: 2097 try:
2183 # Clear existing previews - 立即删除而非 deleteLater,避免布局刷新时序问题 2098 # Clear existing previews
2184 while self.img_layout.count() > 1: # Keep the stretch 2099 while self.img_layout.count() > 1: # Keep the stretch
2185 item = self.img_layout.takeAt(0) 2100 item = self.img_layout.takeAt(0)
2186 widget = item.widget() 2101 if item.widget():
2187 if widget: 2102 item.widget().deleteLater()
2188 widget.setParent(None)
2189 widget.deleteLater()
2190 2103
2191 # Add thumbnails 2104 # Add thumbnails
2192 for idx, file_path in enumerate(self.uploaded_images): 2105 for idx, file_path in enumerate(self.uploaded_images):
2193 self.logger.info(f"创建第 {idx + 1} 张图片缩略图: {file_path}")
2194 try: 2106 try:
2195 # Load and create thumbnail
2196 pixmap = QPixmap(file_path) 2107 pixmap = QPixmap(file_path)
2197 if pixmap.isNull(): 2108 if pixmap.isNull():
2198 self.logger.warning(f"无法加载图片进行预览: {file_path}")
2199 continue 2109 continue
2200 2110
2201 pixmap = pixmap.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation) 2111 pixmap = pixmap.scaled(100, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation)
2202 self.logger.info(f"缩略图创建成功: {pixmap.width()}x{pixmap.height()}")
2203 2112
2204 # Container 2113 # Container
2205 container = QWidget() 2114 container = QWidget()
...@@ -2241,48 +2150,10 @@ class ImageGeneratorWindow(QMainWindow): ...@@ -2241,48 +2150,10 @@ class ImageGeneratorWindow(QMainWindow):
2241 container.setLayout(container_layout) 2150 container.setLayout(container_layout)
2242 2151
2243 self.img_layout.insertWidget(self.img_layout.count() - 1, container) 2152 self.img_layout.insertWidget(self.img_layout.count() - 1, container)
2244 container.show()
2245 self.logger.info(f"缩略图UI组件创建完成: {file_path}")
2246 2153
2247 except Exception as e: 2154 except Exception as e:
2248 self.logger.error(f"创建缩略图失败: {file_path}, 错误: {str(e)}", exc_info=True) 2155 self.logger.error(f"创建缩略图失败: {file_path}, 错误: {str(e)}", exc_info=True)
2249 2156
2250 # 强制刷新布局和滚动区域
2251 self.img_layout.activate()
2252 self.img_container.adjustSize()
2253 self.img_container.repaint()
2254 self.img_scroll.viewport().repaint()
2255
2256 # === 诊断日志:排查缩略图不可见问题 ===
2257 self.logger.info(f"[诊断] img_layout.count = {self.img_layout.count()}")
2258 self.logger.info(f"[诊断] img_container.size = {self.img_container.size().width()}x{self.img_container.size().height()}")
2259 self.logger.info(f"[诊断] img_container.isVisible = {self.img_container.isVisible()}")
2260 self.logger.info(f"[诊断] img_scroll.size = {self.img_scroll.size().width()}x{self.img_scroll.size().height()}")
2261 self.logger.info(f"[诊断] img_scroll.isVisible = {self.img_scroll.isVisible()}")
2262 self.logger.info(f"[诊断] img_scroll.widget = {self.img_scroll.widget()}")
2263 self.logger.info(f"[诊断] img_scroll.widgetResizable = {self.img_scroll.widgetResizable()}")
2264 for i in range(self.img_layout.count()):
2265 item = self.img_layout.itemAt(i)
2266 w = item.widget()
2267 if w:
2268 self.logger.info(
2269 f"[诊断] layout[{i}]: widget={w.__class__.__name__}, "
2270 f"size={w.size().width()}x{w.size().height()}, "
2271 f"sizeHint={w.sizeHint().width()}x{w.sizeHint().height()}, "
2272 f"visible={w.isVisible()}, "
2273 f"geometry={w.geometry()}"
2274 )
2275 # 检查子 widget
2276 for child in w.findChildren(QLabel):
2277 pm = child.pixmap()
2278 self.logger.info(
2279 f"[诊断] QLabel: size={child.size().width()}x{child.size().height()}, "
2280 f"visible={child.isVisible()}, "
2281 f"hasPixmap={pm is not None and not pm.isNull() if pm else False}"
2282 )
2283 else:
2284 self.logger.info(f"[诊断] layout[{i}]: spacer/stretch")
2285
2286 except Exception as e: 2157 except Exception as e:
2287 self.logger.error(f"更新图片预览失败: {str(e)}", exc_info=True) 2158 self.logger.error(f"更新图片预览失败: {str(e)}", exc_info=True)
2288 2159
......