Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
柴进
/
GoogleNanoBananaApp
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
8b46fb30
authored
2026-02-28 12:40:24 +0800
by
柴进
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
清理无用代码
1 parent
e554cf55
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
38 additions
and
167 deletions
image_generator.py
image_generator.py
View file @
8b46fb3
...
...
@@ -1889,69 +1889,25 @@ class ImageGeneratorWindow(QMainWindow):
QMessageBox
.
warning
(
self
,
"警告"
,
"没有找到有效的图片文件"
)
def
add_clipboard_image
(
self
,
image
):
"""添加剪贴板图像(用于拖拽
和粘贴功能
)"""
"""添加剪贴板图像(用于拖拽
图像数据
)"""
try
:
self
.
logger
.
info
(
"开始处理剪贴板图像"
)
# 生成临时文件名
timestamp
=
datetime
.
now
()
.
strftime
(
"
%
Y
%
m
%
d_
%
H
%
M
%
S"
)
temp_dir
=
Path
(
tempfile
.
gettempdir
())
/
"nano_banana_app"
temp_dir
.
mkdir
(
exist_ok
=
True
)
self
.
logger
.
info
(
f
"临时目录: {temp_dir}"
)
temp_file_path
=
temp_dir
/
f
"clipboard_{timestamp}.png"
# 统一使用PNG格式保存,确保跨平台兼容
file_extension
=
".png"
temp_file_path
=
temp_dir
/
f
"clipboard_{timestamp}{file_extension}"
# 尝试多种保存方式,确保兼容性
self
.
logger
.
info
(
f
"QImage信息: {image.width()}x{image.height()}, format={image.format()}, isNull={image.isNull()}"
)
success
=
False
# 方法1: 先转换为 RGB32 格式再保存(避免格式不兼容导致保存异常)
try
:
normalized
=
image
.
convertToFormat
(
QImage
.
Format
.
Format_ARGB32
)
success
=
normalized
.
save
(
str
(
temp_file_path
),
"PNG"
)
self
.
logger
.
info
(
f
"方法1(ARGB32转换)保存结果: {success}"
)
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"方法1保存失败: {e}"
)
# 方法2: 直接保存原始格式
if
not
success
:
try
:
success
=
image
.
save
(
str
(
temp_file_path
),
"PNG"
)
self
.
logger
.
info
(
f
"方法2(原始格式)保存结果: {success}"
)
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"方法2保存失败: {e}"
)
# 方法3: 通过 QPixmap 中转保存
normalized
=
image
.
convertToFormat
(
QImage
.
Format
.
Format_ARGB32
)
success
=
normalized
.
save
(
str
(
temp_file_path
),
"PNG"
)
if
not
success
:
try
:
pixmap
=
QPixmap
.
fromImage
(
image
)
success
=
pixmap
.
save
(
str
(
temp_file_path
),
"PNG"
)
self
.
logger
.
info
(
f
"方法3(QPixmap中转)保存结果: {success}"
)
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"方法3保存失败: {e}"
)
success
=
image
.
save
(
str
(
temp_file_path
),
"PNG"
)
# 验证保存的文件确实可被加载为缩略图
if
success
and
temp_file_path
.
exists
():
file_size
=
temp_file_path
.
stat
()
.
st_size
self
.
logger
.
info
(
f
"保存文件大小: {file_size} bytes"
)
if
file_size
==
0
:
self
.
logger
.
error
(
"保存的文件为空(0字节)"
)
success
=
False
if
success
and
temp_file_path
.
exists
():
if
success
and
temp_file_path
.
exists
()
and
temp_file_path
.
stat
()
.
st_size
>
0
:
self
.
uploaded_images
.
append
(
str
(
temp_file_path
))
self
.
update_image_preview
()
self
.
image_count_label
.
setText
(
f
"已选择 {len(self.uploaded_images)} 张"
)
self
.
status_label
.
setText
(
"● 已添加剪贴板图片"
)
self
.
status_label
.
setStyleSheet
(
"QLabel { color: #34C759; }"
)
self
.
logger
.
info
(
f
"剪贴板图片已成功保存到: {temp_file_path}"
)
# 延迟到下一个事件循环刷新预览,避免 macOS 剪贴板上下文阻塞 UI 更新
QTimer
.
singleShot
(
0
,
self
.
update_image_preview
)
# 检查极速模式下的多图限制
# self.check_multi_image_mode_conflict()
else
:
self
.
logger
.
error
(
"图片保存失败"
)
QMessageBox
.
critical
(
self
,
"错误"
,
"无法保存剪贴板图片"
)
except
Exception
as
e
:
...
...
@@ -1959,42 +1915,34 @@ class ImageGeneratorWindow(QMainWindow):
QMessageBox
.
critical
(
self
,
"错误"
,
f
"添加剪贴板图片失败: {str(e)}"
)
def
_safe_get_clipboard_image
(
self
):
"""安全地从剪贴板获取图像,兼容 macOS 高低版本"""
"""安全地从剪贴板获取纯图像数据(如截图),兼容 macOS 高低版本
注意:Finder 复制的文件应通过 paste_from_clipboard 中的 hasUrls 分支处理,
不会走到这里。此方法只处理纯图像数据(截图、从应用复制的图片等)。
"""
clipboard
=
QApplication
.
clipboard
()
# 方法1: 从 MIME data
的 image formats 读取原始字节构造 QImage
# 方法1: 从 MIME data
读取图像
# 避免直接调用 clipboard.image(),该方法在 macOS 26 可能导致 native crash
try
:
mime_data
=
clipboard
.
mimeData
()
if
mime_data
is
None
:
self
.
logger
.
warning
(
"clipboard.mimeData() 返回 None"
)
else
:
formats
=
list
(
mime_data
.
formats
())
self
.
logger
.
info
(
f
"剪贴板MIME类型: {formats}"
)
# 尝试从常见图像 MIME 格式读取字节数据
image_mime_types
=
[
"image/png"
,
"image/jpeg"
,
"image/bmp"
,
"image/tiff"
,
"application/x-qt-image"
,
]
for
mime_type
in
image_mime_types
:
if
mime_type
in
formats
:
if
mime_data
is
not
None
:
# 尝试从图像 MIME 格式读取原始字节
for
mime_type
in
(
"image/png"
,
"image/jpeg"
,
"image/bmp"
,
"image/tiff"
,
"application/x-qt-image"
):
if
mime_type
in
mime_data
.
formats
():
raw_data
=
mime_data
.
data
(
mime_type
)
if
raw_data
and
len
(
raw_data
)
>
0
:
image
=
QImage
()
if
image
.
loadFromData
(
raw_data
):
self
.
logger
.
info
(
f
"方法1成功: 从 {mime_type} 构造图像 {image.width()}x{image.height()}"
)
return
image
# 尝试 hasImage + imageData
(比 clipboard.image() 更安全)
# 尝试 hasImage + imageData
if
mime_data
.
hasImage
():
image_data
=
mime_data
.
imageData
()
if
image_data
is
not
None
:
if
isinstance
(
image_data
,
QImage
)
and
not
image_data
.
isNull
():
self
.
logger
.
info
(
f
"方法1b成功: imageData() {image_data.width()}x{image_data.height()}"
)
return
image_data
if
isinstance
(
image_data
,
QImage
)
and
not
image_data
.
isNull
():
return
image_data
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"
方法1 (MIME data)
失败: {e}"
)
self
.
logger
.
warning
(
f
"
MIME data 方式获取剪贴板图像
失败: {e}"
)
# 方法2: macOS 专用 - 用 osascript 将剪贴板图片写入临时文件
if
platform
.
system
()
==
"Darwin"
:
...
...
@@ -2002,7 +1950,6 @@ class ImageGeneratorWindow(QMainWindow):
import
subprocess
temp_path
=
Path
(
tempfile
.
gettempdir
())
/
"nano_banana_app"
/
"_clipboard_tmp.png"
temp_path
.
parent
.
mkdir
(
exist_ok
=
True
)
# 删除旧文件
if
temp_path
.
exists
():
temp_path
.
unlink
()
...
...
@@ -2020,48 +1967,38 @@ class ImageGeneratorWindow(QMainWindow):
' error "no image"
\n
'
'end try
\n
'
)
result
=
subprocess
.
run
(
[
"osascript"
,
"-e"
,
script
],
capture_output
=
True
,
timeout
=
5
)
result
=
subprocess
.
run
([
"osascript"
,
"-e"
,
script
],
capture_output
=
True
,
timeout
=
5
)
if
result
.
returncode
==
0
and
temp_path
.
exists
()
and
temp_path
.
stat
()
.
st_size
>
0
:
image
=
QImage
(
str
(
temp_path
))
if
not
image
.
isNull
():
self
.
logger
.
info
(
f
"方法2成功: osascript 读取剪贴板 {image.width()}x{image.height()}"
)
return
image
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"
方法2 (osascript)
失败: {e}"
)
self
.
logger
.
warning
(
f
"
osascript 方式获取剪贴板图像
失败: {e}"
)
# 方法3:
最后手段 - 直接调用 clipboard.image()(低版本 macOS 可靠
)
# 方法3:
直接调用 clipboard.image()(低版本 macOS / Windows / Linux
)
try
:
image
=
clipboard
.
image
()
if
image
and
not
image
.
isNull
():
self
.
logger
.
info
(
f
"方法3成功: clipboard.image() {image.width()}x{image.height()}"
)
return
image
except
Exception
as
e
:
self
.
logger
.
warning
(
f
"
方法3 (clipboard.image
) 失败: {e}"
)
self
.
logger
.
warning
(
f
"
clipboard.image(
) 失败: {e}"
)
return
None
def
paste_from_clipboard
(
self
):
"""从剪贴板粘贴图像"""
try
:
self
.
logger
.
info
(
"开始粘贴剪贴板图片"
)
clipboard
=
QApplication
.
clipboard
()
mime_data
=
clipboard
.
mimeData
()
# 优先处理文件URL(如 Finder 中复制的图片文件)
# 优先处理文件URL(如 Finder
/ 资源管理器
中复制的图片文件)
if
mime_data
and
mime_data
.
hasUrls
():
image_files
=
[]
for
url
in
mime_data
.
urls
():
if
url
.
isLocalFile
():
file_path
=
url
.
toLocalFile
()
self
.
logger
.
info
(
f
"剪贴板包含文件: {file_path}"
)
if
Path
(
file_path
)
.
suffix
.
lower
()
in
{
'.png'
,
'.jpg'
,
'.jpeg'
,
'.gif'
,
'.bmp'
,
'.webp'
}:
image_files
.
append
(
file_path
)
valid_ext
=
{
'.png'
,
'.jpg'
,
'.jpeg'
,
'.gif'
,
'.bmp'
,
'.webp'
}
image_files
=
[
url
.
toLocalFile
()
for
url
in
mime_data
.
urls
()
if
url
.
isLocalFile
()
and
Path
(
url
.
toLocalFile
())
.
suffix
.
lower
()
in
valid_ext
]
if
image_files
:
self
.
logger
.
info
(
f
"从剪贴板文件URL添加 {len(image_files)} 张图片"
)
added
=
0
for
fp
in
image_files
:
if
self
.
validate_image_file
(
fp
):
...
...
@@ -2074,16 +2011,12 @@ class ImageGeneratorWindow(QMainWindow):
self
.
status_label
.
setStyleSheet
(
"QLabel { color: #34C759; }"
)
return
# 没有文件URL,尝试获取
剪贴板中的图像数据(如截图、从应用复制的图片
)
# 没有文件URL,尝试获取
纯图像数据(截图、从应用复制的图片等
)
image
=
self
.
_safe_get_clipboard_image
()
if
image
is
None
:
self
.
logger
.
warning
(
"剪贴板中没有可用的图像"
)
QMessageBox
.
information
(
self
,
"信息"
,
"剪贴板中没有图片,请先复制一张图片"
)
return
self
.
logger
.
info
(
f
"成功获取剪贴板图像数据: {image.width()}x{image.height()}"
)
# 保存到临时文件
timestamp
=
datetime
.
now
()
.
strftime
(
"
%
Y
%
m
%
d_
%
H
%
M
%
S_
%
f"
)
temp_dir
=
Path
(
tempfile
.
gettempdir
())
/
"nano_banana_app"
...
...
@@ -2093,11 +2026,9 @@ class ImageGeneratorWindow(QMainWindow):
normalized
=
image
.
convertToFormat
(
QImage
.
Format
.
Format_ARGB32
)
if
not
normalized
.
save
(
temp_file_path
,
"PNG"
):
if
not
image
.
save
(
temp_file_path
,
"PNG"
):
self
.
logger
.
error
(
"剪贴板图片保存失败"
)
QMessageBox
.
critical
(
self
,
"错误"
,
"无法保存剪贴板图片"
)
return
self
.
logger
.
info
(
f
"剪贴板图片已保存: {temp_file_path}"
)
self
.
uploaded_images
.
append
(
temp_file_path
)
self
.
update_image_preview
()
self
.
image_count_label
.
setText
(
f
"已选择 {len(self.uploaded_images)} 张"
)
...
...
@@ -2105,7 +2036,7 @@ class ImageGeneratorWindow(QMainWindow):
self
.
status_label
.
setStyleSheet
(
"QLabel { color: #34C759; }"
)
except
Exception
as
e
:
self
.
logger
.
error
(
f
"粘贴
剪贴板图片时发生错误: {str(e)
}"
,
exc_info
=
True
)
self
.
logger
.
error
(
f
"粘贴
失败: {e
}"
,
exc_info
=
True
)
QMessageBox
.
critical
(
self
,
"错误"
,
f
"粘贴失败: {str(e)}"
)
def
validate_image_file
(
self
,
file_path
:
str
)
->
bool
:
...
...
@@ -2153,53 +2084,31 @@ class ImageGeneratorWindow(QMainWindow):
def
keyPressEvent
(
self
,
event
):
"""处理键盘事件"""
# 检测键盘组合键
key_text
=
event
.
text
()
key_int
=
event
.
key
()
modifiers
=
event
.
modifiers
()
self
.
logger
.
info
(
f
"键盘事件: key={key_int}, text='{key_text}', modifiers={modifiers}"
)
# Ctrl+V 粘贴
if
event
.
key
()
==
Qt
.
Key_V
and
event
.
modifiers
()
==
Qt
.
ControlModifier
:
self
.
logger
.
info
(
"检测到 Ctrl+V 粘贴组合键"
)
# Ctrl+V / Cmd+V 粘贴
if
event
.
key
()
==
Qt
.
Key_V
and
event
.
modifiers
()
in
(
Qt
.
ControlModifier
,
Qt
.
MetaModifier
):
self
.
paste_from_clipboard
()
event
.
accept
()
return
# Cmd+V 粘贴 (macOS)
elif
event
.
key
()
==
Qt
.
Key_V
and
event
.
modifiers
()
==
Qt
.
MetaModifier
:
self
.
logger
.
info
(
"检测到 Cmd+V 粘贴组合键 (macOS)"
)
self
.
paste_from_clipboard
()
event
.
accept
()
return
self
.
logger
.
debug
(
f
"未处理的键盘事件: {key_text}"
)
super
()
.
keyPressEvent
(
event
)
def
update_image_preview
(
self
):
"""Update image preview thumbnails"""
self
.
logger
.
info
(
f
"更新图片预览,共 {len(self.uploaded_images)} 张图片"
)
try
:
# Clear existing previews
- 立即删除而非 deleteLater,避免布局刷新时序问题
# Clear existing previews
while
self
.
img_layout
.
count
()
>
1
:
# Keep the stretch
item
=
self
.
img_layout
.
takeAt
(
0
)
widget
=
item
.
widget
()
if
widget
:
widget
.
setParent
(
None
)
widget
.
deleteLater
()
if
item
.
widget
():
item
.
widget
()
.
deleteLater
()
# Add thumbnails
for
idx
,
file_path
in
enumerate
(
self
.
uploaded_images
):
self
.
logger
.
info
(
f
"创建第 {idx + 1} 张图片缩略图: {file_path}"
)
try
:
# Load and create thumbnail
pixmap
=
QPixmap
(
file_path
)
if
pixmap
.
isNull
():
self
.
logger
.
warning
(
f
"无法加载图片进行预览: {file_path}"
)
continue
pixmap
=
pixmap
.
scaled
(
100
,
100
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
self
.
logger
.
info
(
f
"缩略图创建成功: {pixmap.width()}x{pixmap.height()}"
)
# Container
container
=
QWidget
()
...
...
@@ -2241,48 +2150,10 @@ class ImageGeneratorWindow(QMainWindow):
container
.
setLayout
(
container_layout
)
self
.
img_layout
.
insertWidget
(
self
.
img_layout
.
count
()
-
1
,
container
)
container
.
show
()
self
.
logger
.
info
(
f
"缩略图UI组件创建完成: {file_path}"
)
except
Exception
as
e
:
self
.
logger
.
error
(
f
"创建缩略图失败: {file_path}, 错误: {str(e)}"
,
exc_info
=
True
)
# 强制刷新布局和滚动区域
self
.
img_layout
.
activate
()
self
.
img_container
.
adjustSize
()
self
.
img_container
.
repaint
()
self
.
img_scroll
.
viewport
()
.
repaint
()
# === 诊断日志:排查缩略图不可见问题 ===
self
.
logger
.
info
(
f
"[诊断] img_layout.count = {self.img_layout.count()}"
)
self
.
logger
.
info
(
f
"[诊断] img_container.size = {self.img_container.size().width()}x{self.img_container.size().height()}"
)
self
.
logger
.
info
(
f
"[诊断] img_container.isVisible = {self.img_container.isVisible()}"
)
self
.
logger
.
info
(
f
"[诊断] img_scroll.size = {self.img_scroll.size().width()}x{self.img_scroll.size().height()}"
)
self
.
logger
.
info
(
f
"[诊断] img_scroll.isVisible = {self.img_scroll.isVisible()}"
)
self
.
logger
.
info
(
f
"[诊断] img_scroll.widget = {self.img_scroll.widget()}"
)
self
.
logger
.
info
(
f
"[诊断] img_scroll.widgetResizable = {self.img_scroll.widgetResizable()}"
)
for
i
in
range
(
self
.
img_layout
.
count
()):
item
=
self
.
img_layout
.
itemAt
(
i
)
w
=
item
.
widget
()
if
w
:
self
.
logger
.
info
(
f
"[诊断] layout[{i}]: widget={w.__class__.__name__}, "
f
"size={w.size().width()}x{w.size().height()}, "
f
"sizeHint={w.sizeHint().width()}x{w.sizeHint().height()}, "
f
"visible={w.isVisible()}, "
f
"geometry={w.geometry()}"
)
# 检查子 widget
for
child
in
w
.
findChildren
(
QLabel
):
pm
=
child
.
pixmap
()
self
.
logger
.
info
(
f
"[诊断] QLabel: size={child.size().width()}x{child.size().height()}, "
f
"visible={child.isVisible()}, "
f
"hasPixmap={pm is not None and not pm.isNull() if pm else False}"
)
else
:
self
.
logger
.
info
(
f
"[诊断] layout[{i}]: spacer/stretch"
)
except
Exception
as
e
:
self
.
logger
.
error
(
f
"更新图片预览失败: {str(e)}"
,
exc_info
=
True
)
...
...
Please
register
or
sign in
to post a comment