You've already forked Nano-Banana-AI-Image-Editor
修复内存溢出问题
This commit is contained in:
@@ -61,10 +61,10 @@ export const HistoryPanel: React.FC = () => {
|
||||
|
||||
// 分页状态
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const itemsPerPage = 30; // 每页显示的项目数
|
||||
const itemsPerPage = 20; // 减少每页显示的项目数
|
||||
|
||||
// 悬浮预览状态
|
||||
const [hoveredImage, setHoveredImage] = useState<{url: string, title: string, width?: number, height?: number, size?: number} | null>(null);
|
||||
const [hoveredImage, setHoveredImage] = useState<{url: string, title: string, width?: number, height?: number} | null>(null);
|
||||
const [previewPosition, setPreviewPosition] = useState<{x: number, y: number}>({x: 0, y: 0});
|
||||
|
||||
const generations = currentProject?.generations || [];
|
||||
@@ -76,7 +76,7 @@ export const HistoryPanel: React.FC = () => {
|
||||
const uploadResult = generationOrEdit.uploadResults[index];
|
||||
if (uploadResult.success && uploadResult.url) {
|
||||
// 添加参数以降低图片质量
|
||||
return `${uploadResult.url}?x-oss-process=image/quality,q_50`;
|
||||
return `${uploadResult.url}?x-oss-process=image/quality,q_30`; // 降低质量到30%
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -480,7 +480,7 @@ export const HistoryPanel: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wide">变体</h4>
|
||||
<span className="text-xs text-gray-400">
|
||||
{filteredGenerations.length + filteredEdits.length}/1000
|
||||
{filteredGenerations.length + filteredEdits.length}/100
|
||||
</span>
|
||||
</div>
|
||||
{filteredGenerations.length === 0 && filteredEdits.length === 0 ? (
|
||||
@@ -530,25 +530,16 @@ export const HistoryPanel: React.FC = () => {
|
||||
// 创建图像对象以获取尺寸
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
// 计算文件大小(仅对base64数据)
|
||||
let size = 0;
|
||||
if (imageUrl.startsWith('data:')) {
|
||||
// 估算base64数据大小
|
||||
const base64Data = imageUrl.split(',')[1];
|
||||
size = Math.round((base64Data.length * 3) / 4);
|
||||
}
|
||||
|
||||
setHoveredImage({
|
||||
url: imageUrl,
|
||||
title: `生成记录 G${globalIndex + 1}`,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
size: size
|
||||
height: img.height
|
||||
});
|
||||
|
||||
// 计算预览位置,确保不超出屏幕边界
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300; // 减小预览窗口大小
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -596,13 +587,12 @@ export const HistoryPanel: React.FC = () => {
|
||||
url: imageUrl,
|
||||
title: `生成记录 G${globalIndex + 1}`,
|
||||
width: 0,
|
||||
height: 0,
|
||||
size: 0
|
||||
height: 0
|
||||
});
|
||||
|
||||
// 计算预览位置
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -641,8 +631,8 @@ export const HistoryPanel: React.FC = () => {
|
||||
}}
|
||||
onMouseMove={(e) => {
|
||||
// 调整预览位置以避免被遮挡
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -688,9 +678,9 @@ export const HistoryPanel: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
// 优先使用上传后的远程链接,如果没有则使用原始链接
|
||||
// 优先使用上传后的远程链接
|
||||
const imageUrl = getUploadedImageUrl(generation, 0) ||
|
||||
(generation.outputAssets && generation.outputAssets.length > 0 ? generation.outputAssets[0].url : null);
|
||||
(generation.outputAssets && generation.outputAssets.length > 0 && generation.outputAssets[0].url ? generation.outputAssets[0].url : null);
|
||||
|
||||
if (imageUrl) {
|
||||
return <img src={imageUrl} alt="生成的变体" className="w-full h-full object-cover" />;
|
||||
@@ -757,25 +747,16 @@ export const HistoryPanel: React.FC = () => {
|
||||
// 创建图像对象以获取尺寸
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
// 计算文件大小(仅对base64数据)
|
||||
let size = 0;
|
||||
if (imageUrl.startsWith('data:')) {
|
||||
// 估算base64数据大小
|
||||
const base64Data = imageUrl.split(',')[1];
|
||||
size = Math.round((base64Data.length * 3) / 4);
|
||||
}
|
||||
|
||||
setHoveredImage({
|
||||
url: imageUrl,
|
||||
title: `编辑记录 E${globalIndex + 1}`,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
size: size
|
||||
height: img.height
|
||||
});
|
||||
|
||||
// 计算预览位置,确保不超出屏幕边界
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -816,13 +797,12 @@ export const HistoryPanel: React.FC = () => {
|
||||
url: imageUrl,
|
||||
title: `编辑记录 E${globalIndex + 1}`,
|
||||
width: 0,
|
||||
height: 0,
|
||||
size: 0
|
||||
height: 0
|
||||
});
|
||||
|
||||
// 计算预览位置
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -865,8 +845,8 @@ export const HistoryPanel: React.FC = () => {
|
||||
}}
|
||||
onMouseMove={(e) => {
|
||||
// 调整预览位置以避免被遮挡
|
||||
const previewWidth = 500;
|
||||
const previewHeight = 500;
|
||||
const previewWidth = 300;
|
||||
const previewHeight = 300;
|
||||
const offsetX = 10;
|
||||
const offsetY = 10;
|
||||
|
||||
@@ -904,9 +884,9 @@ export const HistoryPanel: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
// 优先使用上传后的远程链接,如果没有则使用原始链接
|
||||
// 优先使用上传后的远程链接
|
||||
const imageUrl = getUploadedImageUrl(edit, 0) ||
|
||||
(edit.outputAssets && edit.outputAssets.length > 0 ? edit.outputAssets[0].url : null);
|
||||
(edit.outputAssets && edit.outputAssets.length > 0 && edit.outputAssets[0].url ? edit.outputAssets[0].url : null);
|
||||
|
||||
if (imageUrl) {
|
||||
return <img src={imageUrl} alt="编辑的变体" className="w-full h-full object-cover" />;
|
||||
@@ -1042,7 +1022,7 @@ export const HistoryPanel: React.FC = () => {
|
||||
// 获取上传后的远程链接(如果存在)
|
||||
// 参考图像在uploadResults中从索引1开始(索引0是生成的图像)
|
||||
const uploadedUrl = gen.uploadResults && gen.uploadResults[index + 1] && gen.uploadResults[index + 1].success
|
||||
? `${gen.uploadResults[index + 1].url}?x-oss-process=image/quality,q_50`
|
||||
? `${gen.uploadResults[index + 1].url}?x-oss-process=image/quality,q_30`
|
||||
: null;
|
||||
const displayUrl = uploadedUrl || asset.url;
|
||||
|
||||
@@ -1150,7 +1130,7 @@ export const HistoryPanel: React.FC = () => {
|
||||
// 获取上传后的远程链接(如果存在)
|
||||
// 参考图像在uploadResults中从索引1开始(索引0是生成的图像)
|
||||
const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[index + 1] && parentGen.uploadResults[index + 1].success
|
||||
? `${parentGen.uploadResults[index + 1].url}?x-oss-process=image/quality,q_50`
|
||||
? `${parentGen.uploadResults[index + 1].url}?x-oss-process=image/quality,q_30`
|
||||
: null;
|
||||
const displayUrl = uploadedUrl || asset.url;
|
||||
|
||||
@@ -1219,7 +1199,25 @@ export const HistoryPanel: React.FC = () => {
|
||||
|
||||
if (imageUrl) {
|
||||
// 处理数据URL和常规URL
|
||||
if (imageUrl.startsWith('data:')) {
|
||||
if (imageUrl.startsWith('data:') || imageUrl.startsWith('blob:')) {
|
||||
// 对于Blob URL,我们需要获取实际的Blob数据
|
||||
if (imageUrl.startsWith('blob:')) {
|
||||
// 从AppStore获取Blob
|
||||
const blob = useAppStore.getState().getBlob(imageUrl);
|
||||
if (blob) {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `nano-banana-${Date.now()}.png`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 对于数据URL,直接下载
|
||||
const link = document.createElement('a');
|
||||
link.href = imageUrl;
|
||||
link.download = `nano-banana-${Date.now()}.png`;
|
||||
@@ -1266,8 +1264,8 @@ export const HistoryPanel: React.FC = () => {
|
||||
style={{
|
||||
left: `${previewPosition.x}px`,
|
||||
top: `${previewPosition.y}px`,
|
||||
maxWidth: '300px',
|
||||
maxHeight: '300px'
|
||||
maxWidth: '200px', // 减小最大宽度
|
||||
maxHeight: '200px'
|
||||
}}
|
||||
>
|
||||
<div className="bg-gray-900 text-white text-xs p-2 truncate font-medium">
|
||||
@@ -1276,7 +1274,7 @@ export const HistoryPanel: React.FC = () => {
|
||||
<img
|
||||
src={hoveredImage.url}
|
||||
alt="预览"
|
||||
className="w-full h-auto max-h-[200px] object-contain"
|
||||
className="w-full h-auto max-h-[150px] object-contain"
|
||||
/>
|
||||
{/* 图像信息 */}
|
||||
<div className="p-2 bg-gray-50 border-t border-gray-200 text-xs">
|
||||
@@ -1286,12 +1284,6 @@ export const HistoryPanel: React.FC = () => {
|
||||
<span className="text-gray-800">{hoveredImage.width} × {hoveredImage.height}</span>
|
||||
</div>
|
||||
)}
|
||||
{hoveredImage.size > 0 && (
|
||||
<div className="flex justify-between text-gray-600 mt-1">
|
||||
<span>大小:</span>
|
||||
<span className="text-gray-800">{Math.round(hoveredImage.size / 1024)} KB</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user