diff --git a/src/components/HistoryPanel.tsx b/src/components/HistoryPanel.tsx index dd2c7e2..6840157 100644 --- a/src/components/HistoryPanel.tsx +++ b/src/components/HistoryPanel.tsx @@ -630,16 +630,76 @@ export const HistoryPanel: React.FC<{ }; img.onerror = (error) => { console.error('图像加载失败:', error); - // 即使图像加载失败,也显示预览 - setHoveredImage({ - url: imageUrl, - title: `生成记录 G${globalIndex + 1}`, - width: 0, - height: 0 - }); - // 传递鼠标位置信息给App组件 - if (setPreviewPosition) { - setPreviewPosition({ x: e.clientX, y: e.clientY }); + // 如果是Blob URL失效,尝试重新获取 + if (imageUrl.startsWith('blob:')) { + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(imageUrl); + if (blob) { + console.log('从AppStore找到Blob,尝试重新创建URL...'); + // 重新创建Blob URL + const newUrl = URL.createObjectURL(blob); + // 更新显示 + setHoveredImage({ + url: newUrl, + title: `生成记录 G${globalIndex + 1}`, + width: 0, + height: 0 + }); + // 传递鼠标位置信息给App组件 + if (setPreviewPosition) { + setPreviewPosition({ x: e.clientX, y: e.clientY }); + } + // 预加载新URL + const newImg = new Image(); + newImg.onload = () => { + setHoveredImage({ + url: newUrl, + title: `生成记录 G${globalIndex + 1}`, + width: newImg.width, + height: newImg.height + }); + }; + newImg.src = newUrl; + } else { + // 即使图像加载失败,也显示预览 + setHoveredImage({ + url: imageUrl, + title: `生成记录 G${globalIndex + 1}`, + width: 0, + height: 0 + }); + // 传递鼠标位置信息给App组件 + if (setPreviewPosition) { + setPreviewPosition({ x: e.clientX, y: e.clientY }); + } + } + }).catch(err => { + console.error('导入AppStore时出错:', err); + // 即使图像加载失败,也显示预览 + setHoveredImage({ + url: imageUrl, + title: `生成记录 G${globalIndex + 1}`, + width: 0, + height: 0 + }); + // 传递鼠标位置信息给App组件 + if (setPreviewPosition) { + setPreviewPosition({ x: e.clientX, y: e.clientY }); + } + }); + } else { + // 即使图像加载失败,也显示预览 + setHoveredImage({ + url: imageUrl, + title: `生成记录 G${globalIndex + 1}`, + width: 0, + height: 0 + }); + // 传递鼠标位置信息给App组件 + if (setPreviewPosition) { + setPreviewPosition({ x: e.clientX, y: e.clientY }); + } } }; img.src = imageUrl; @@ -1026,7 +1086,30 @@ export const HistoryPanel: React.FC<{ ? `${gen.uploadResults[index].url}?x-oss-process=image/quality,q_30` : null; - const displayUrl = uploadedUrl || asset.url; + // 如果没有上传的URL,则使用asset中的URL + const displayUrl = uploadedUrl || asset.url || asset.blobUrl; + + // 如果URL是blob:开头但已失效,尝试重新创建 + if (displayUrl && displayUrl.startsWith('blob:')) { + // 检查blob是否仍然有效 + const img = new Image(); + img.onerror = () => { + // Blob URL可能已失效,尝试重新创建 + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + // 更新显示 + const imgElement = document.querySelector(`img[src="${displayUrl}"]`); + if (imgElement) { + imgElement.src = newUrl; + } + } + }); + }; + img.src = displayUrl; + } return (
- {`生成结果 + {displayUrl ? ( + {`生成结果 { + // 如果图像加载失败,尝试重新创建Blob URL + if (displayUrl.startsWith('blob:')) { + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + (e.target as HTMLImageElement).src = newUrl; + } + }); + } + }} + /> + ) : ( +
+ +
+ )}
); })} @@ -1074,11 +1176,36 @@ export const HistoryPanel: React.FC<{ const fullGen = dbGenerations.find(item => item.id === gen.id) || gen; const outputAssetsCount = fullGen.outputAssets?.length || 0; - const uploadedUrl = gen.uploadResults && gen.uploadResults[outputAssetsCount + index] && gen.uploadResults[outputAssetsCount + index].success - ? `${gen.uploadResults[outputAssetsCount + index].url}?x-oss-process=image/quality,q_30` + // 确保索引在有效范围内 + const uploadResultIndex = outputAssetsCount + index; + const uploadedUrl = fullGen.uploadResults && fullGen.uploadResults[uploadResultIndex] && fullGen.uploadResults[uploadResultIndex].success + ? `${fullGen.uploadResults[uploadResultIndex].url}?x-oss-process=image/quality,q_30` : null; - const displayUrl = uploadedUrl || asset.url; + // 如果没有上传的URL,则使用asset中的URL + const displayUrl = uploadedUrl || asset.url || asset.blobUrl; + + // 如果URL是blob:开头但已失效,尝试重新创建 + if (displayUrl && displayUrl.startsWith('blob:')) { + // 检查blob是否仍然有效 + const img = new Image(); + img.onerror = () => { + // Blob URL可能已失效,尝试重新创建 + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + // 更新显示 + const imgElement = document.querySelector(`img[src="${displayUrl}"]`); + if (imgElement) { + imgElement.src = newUrl; + } + } + }); + }; + img.src = displayUrl; + } return (
- {`参考图像 + {displayUrl ? ( + {`参考图像 { + // 如果图像加载失败,尝试重新创建Blob URL + if (displayUrl.startsWith('blob:')) { + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + (e.target as HTMLImageElement).src = newUrl; + } + }); + } + }} + /> + ) : ( +
+ +
+ )}
); })} @@ -1166,6 +1312,95 @@ export const HistoryPanel: React.FC<{ )} + {/* 编辑结果图像 */} + {selectedEdit.outputAssets && selectedEdit.outputAssets.length > 0 && ( +
+
编辑结果
+
+ {selectedEdit.outputAssets.length} 个编辑结果 +
+
+ {selectedEdit.outputAssets.slice(0, 4).map((asset: any, index: number) => { + // 获取上传后的远程链接(如果存在) + const uploadedUrl = selectedEdit.uploadResults && selectedEdit.uploadResults[index] && selectedEdit.uploadResults[index].success + ? `${selectedEdit.uploadResults[index].url}?x-oss-process=image/quality,q_30` + : null; + + // 如果没有上传的URL,则使用asset中的URL + const displayUrl = uploadedUrl || asset.url || asset.blobUrl; + + // 如果URL是blob:开头但已失效,尝试重新创建 + if (displayUrl && displayUrl.startsWith('blob:')) { + // 检查blob是否仍然有效 + const img = new Image(); + img.onerror = () => { + // Blob URL可能已失效,尝试重新创建 + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + // 更新显示 + const imgElement = document.querySelector(`img[src="${displayUrl}"]`); + if (imgElement) { + imgElement.src = newUrl; + } + } + }); + }; + img.src = displayUrl; + } + + return ( +
{ + e.stopPropagation(); + setPreviewModal({ + open: true, + imageUrl: displayUrl, + title: `编辑结果 ${index + 1}`, + description: `${asset.width} × ${asset.height}` + }); + }} + > + {displayUrl ? ( + {`编辑结果 { + // 如果图像加载失败,尝试重新创建Blob URL + if (displayUrl.startsWith('blob:')) { + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + (e.target as HTMLImageElement).src = newUrl; + } + }); + } + }} + /> + ) : ( +
+ +
+ )} +
+ ); + })} + {selectedEdit.outputAssets.length > 4 && ( +
+ +{selectedEdit.outputAssets.length - 4} +
+ )} +
+
+ )} + {/* 原始生成参考 */} {parentGen && (
@@ -1184,10 +1419,37 @@ export const HistoryPanel: React.FC<{ // 获取上传后的远程链接(如果存在) // 参考图像在uploadResults中从索引outputAssets.length开始 const outputAssetsCount = parentGen.outputAssets?.length || 0; - const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[outputAssetsCount + index] && parentGen.uploadResults[outputAssetsCount + index].success - ? `${parentGen.uploadResults[outputAssetsCount + index].url}?x-oss-process=image/quality,q_30` + + // 确保索引在有效范围内 + const uploadResultIndex = outputAssetsCount + index; + const uploadedUrl = parentGen.uploadResults && parentGen.uploadResults[uploadResultIndex] && parentGen.uploadResults[uploadResultIndex].success + ? `${parentGen.uploadResults[uploadResultIndex].url}?x-oss-process=image/quality,q_30` : null; - const displayUrl = uploadedUrl || asset.url; + + // 如果没有上传的URL,则使用asset中的URL + const displayUrl = uploadedUrl || asset.url || asset.blobUrl; + + // 如果URL是blob:开头但已失效,尝试重新创建 + if (displayUrl && displayUrl.startsWith('blob:')) { + // 检查blob是否仍然有效 + const img = new Image(); + img.onerror = () => { + // Blob URL可能已失效,尝试重新创建 + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + // 更新显示 + const imgElement = document.querySelector(`img[src="${displayUrl}"]`); + if (imgElement) { + imgElement.src = newUrl; + } + } + }); + }; + img.src = displayUrl; + } return (
- {`原始参考图像 + {displayUrl ? ( + {`原始参考图像 { + // 如果图像加载失败,尝试重新创建Blob URL + if (displayUrl.startsWith('blob:')) { + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(displayUrl); + if (blob) { + const newUrl = URL.createObjectURL(blob); + (e.target as HTMLImageElement).src = newUrl; + } + }); + } + }} + /> + ) : ( +
+ +
+ )}
); })} diff --git a/src/components/ImageCanvas.tsx b/src/components/ImageCanvas.tsx index 10e6f97..a79d6bd 100644 --- a/src/components/ImageCanvas.tsx +++ b/src/components/ImageCanvas.tsx @@ -119,6 +119,23 @@ export const ImageCanvas: React.FC = () => { .then(response => { if (!response.ok) { console.error('Blob URL无法访问:', response.status, response.statusText); + // 尝试从AppStore重新获取Blob并创建新的URL + import('../store/useAppStore').then((module) => { + const useAppStore = module.useAppStore; + const blob = useAppStore.getState().getBlob(canvasImage); + if (blob) { + console.log('从AppStore找到Blob,尝试重新创建URL...'); + // 重新创建Blob URL并重试加载 + const newUrl = URL.createObjectURL(blob); + console.log('创建新的Blob URL:', newUrl); + // 更新canvasImage为新的URL + useAppStore.getState().setCanvasImage(newUrl); + } else { + console.error('AppStore中未找到Blob'); + } + }).catch(err => { + console.error('导入AppStore时出错:', err); + }); } else { console.log('Blob URL可以访问'); } diff --git a/src/components/PromptComposer.tsx b/src/components/PromptComposer.tsx index 6865fae..6f0dbd8 100644 --- a/src/components/PromptComposer.tsx +++ b/src/components/PromptComposer.tsx @@ -69,6 +69,27 @@ export const PromptComposer: React.FC = () => { const blob = getBlob(img); if (blob) { referenceImageBlobs.push(blob); + } else { + // 如果在AppStore中找不到Blob,尝试重新创建 + try { + const response = await fetch(img); + if (response.ok) { + const blob = await response.blob(); + // 重新添加到AppStore + const newUrl = useAppStore.getState().addBlob(blob); + referenceImageBlobs.push(blob); + // 更新uploadedImages中的URL + const index = uploadedImages.indexOf(img); + if (index !== -1) { + const newImages = [...uploadedImages]; + newImages[index] = newUrl; + useAppStore.getState().clearUploadedImages(); + newImages.forEach(imageUrl => useAppStore.getState().addUploadedImage(imageUrl)); + } + } + } catch (error) { + console.warn('无法重新获取参考图像:', img, error); + } } } else { // 从URL获取Blob diff --git a/src/hooks/useImageGeneration.ts b/src/hooks/useImageGeneration.ts index 0411cfe..6d4659d 100644 --- a/src/hooks/useImageGeneration.ts +++ b/src/hooks/useImageGeneration.ts @@ -275,6 +275,34 @@ export const useImageEditing = () => { const blob = useAppStore.getState().getBlob(img); if (blob) { referenceImageBlobs.push(blob); + } else { + // 如果在AppStore中找不到Blob,尝试重新获取 + try { + const response = await fetch(img); + if (response.ok) { + const blob = await response.blob(); + referenceImageBlobs.push(blob); + // 重新添加到AppStore + const newUrl = useAppStore.getState().addBlob(blob); + // 更新editReferenceImages中的URL + const index = editReferenceImages.indexOf(img); + if (index !== -1) { + const { removeEditReferenceImage, addEditReferenceImage } = useAppStore.getState(); + removeEditReferenceImage(index); + // 重新添加所有图像以保持顺序 + const currentImages = [...editReferenceImages]; + currentImages[index] = newUrl; + // 清空并重新添加 + for (let i = 0; i < currentImages.length; i++) { + if (i < 2) { // 最多2张参考图像 + addEditReferenceImage(currentImages[i]); + } + } + } + } + } catch (error) { + console.warn('无法重新获取参考图像:', img, error); + } } } else if (img.includes('base64,')) { // 从base64数据创建Blob diff --git a/src/store/useAppStore.ts b/src/store/useAppStore.ts index c635875..e9bf353 100644 --- a/src/store/useAppStore.ts +++ b/src/store/useAppStore.ts @@ -637,8 +637,25 @@ export const useAppStore = create()( const isUsedInUploads = state.uploadedImages.includes(url); const isUsedInEdits = state.editReferenceImages.includes(url); + // 检查是否是历史记录中的参考图像 + const isUsedAsReference = state.currentProject && ( + state.currentProject.generations.some(gen => + gen.sourceAssets.some(asset => asset.blobUrl === url) + ) || + state.currentProject.edits.some(edit => + (edit.maskReferenceAssetBlobUrl === url) + ) + ); + + // 检查是否是当前编辑操作中的参考图像 + const isUsedInCurrentEdit = state.editReferenceImages.includes(url); + + // 检查是否是当前生成操作中的参考图像 + const isUsedInCurrentGeneration = state.uploadedImages.includes(url); + // 如果Blob没有被使用,则清理它 - if (!isUsedInProject && !isUsedInCanvas && !isUsedInUploads && !isUsedInEdits) { + // 但保留仍在作为参考图像使用的Blob + if (!isUsedInProject && !isUsedInCanvas && !isUsedInUploads && !isUsedInEdits && !isUsedAsReference && !isUsedInCurrentEdit && !isUsedInCurrentGeneration) { URL.revokeObjectURL(url); const newBlobStore = new Map(state.blobStore); newBlobStore.delete(url);