重构: 优化indexedDBStorage中的图像存储和uiController中的URL处理逻辑,确保Blob URL和Base64数据的一致性。
This commit is contained in:
205
script.js
205
script.js
@@ -58,6 +58,12 @@ const utils = {
|
|||||||
return base64Data;
|
return base64Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否是base64数据格式
|
||||||
|
if (!base64Data.startsWith('data:image/')) {
|
||||||
|
console.warn('Not a valid base64 image format, returning original data');
|
||||||
|
return base64Data;
|
||||||
|
}
|
||||||
|
|
||||||
// 提取base64数据的MIME类型和纯数据部分
|
// 提取base64数据的MIME类型和纯数据部分
|
||||||
const parts = base64Data.split(';base64,');
|
const parts = base64Data.split(';base64,');
|
||||||
if (parts.length !== 2) {
|
if (parts.length !== 2) {
|
||||||
@@ -399,15 +405,43 @@ const indexedDBStorage = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const transaction = this.db.transaction([CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES], 'readwrite');
|
// 首先处理图像URL,获取要存储的数据
|
||||||
const store = transaction.objectStore(CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES);
|
|
||||||
|
|
||||||
// 检查是否是Blob URL,如果是则获取原始base64数据
|
|
||||||
let storedUrl = imageUrl;
|
let storedUrl = imageUrl;
|
||||||
if (imageUrl.startsWith('blob:') && imageUrl._originalBase64) {
|
if (imageUrl.startsWith('blob:') && imageUrl._originalBase64) {
|
||||||
storedUrl = imageUrl._originalBase64;
|
storedUrl = imageUrl._originalBase64;
|
||||||
|
console.log('Storing original base64 data for image');
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 已经是base64格式,直接存储
|
||||||
|
console.log('Image is already in base64 format, storing directly');
|
||||||
|
} else if (imageUrl.startsWith('blob:')) {
|
||||||
|
// Blob URL没有原始base64数据,需要从Blob URL中提取base64数据
|
||||||
|
console.warn('Blob URL has no original base64 data, attempting to extract base64 data from Blob');
|
||||||
|
try {
|
||||||
|
// 通过fetch获取Blob数据,然后转换为base64
|
||||||
|
const response = await fetch(imageUrl);
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
// 将Blob转换为base64
|
||||||
|
const reader = new FileReader();
|
||||||
|
const base64Promise = new Promise((resolve, reject) => {
|
||||||
|
reader.onload = () => resolve(reader.result);
|
||||||
|
reader.onerror = reject;
|
||||||
|
});
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
|
||||||
|
storedUrl = await base64Promise;
|
||||||
|
console.log('Successfully extracted base64 data from Blob URL');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to extract base64 data from Blob URL:', error);
|
||||||
|
// 如果转换失败,仍然存储原始URL,但记录警告
|
||||||
|
console.warn('Storing original Blob URL, which may cause issues after page reload');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 现在创建事务并存储数据
|
||||||
|
const transaction = this.db.transaction([CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES], 'readwrite');
|
||||||
|
const store = transaction.objectStore(CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES);
|
||||||
|
|
||||||
const image = {
|
const image = {
|
||||||
imageId: imageId,
|
imageId: imageId,
|
||||||
url: storedUrl,
|
url: storedUrl,
|
||||||
@@ -717,7 +751,9 @@ const apiService = {
|
|||||||
// 提取图像数据并转换为Blob URL,但保留原始base64数据
|
// 提取图像数据并转换为Blob URL,但保留原始base64数据
|
||||||
if (choice.message.images) {
|
if (choice.message.images) {
|
||||||
choice.message.images.forEach(img => {
|
choice.message.images.forEach(img => {
|
||||||
const blobUrl = utils.base64ToBlobUrl(img.image_url.url);
|
// 确保原始数据是base64格式
|
||||||
|
const originalBase64 = img.image_url.url;
|
||||||
|
const blobUrl = utils.base64ToBlobUrl(originalBase64);
|
||||||
images.push(blobUrl);
|
images.push(blobUrl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -821,7 +857,23 @@ const uiController = {
|
|||||||
const imageId = Date.now() + Math.random();
|
const imageId = Date.now() + Math.random();
|
||||||
|
|
||||||
// 确保imageUrl是Blob URL用于显示,但保存原始URL用于存储
|
// 确保imageUrl是Blob URL用于显示,但保存原始URL用于存储
|
||||||
const displayUrl = imageUrl.startsWith('blob:') ? imageUrl : utils.base64ToBlobUrl(imageUrl);
|
let displayUrl;
|
||||||
|
let originalUrl = imageUrl; // 原始URL,可能是base64或Blob URL
|
||||||
|
|
||||||
|
if (imageUrl.startsWith('blob:')) {
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
displayUrl = utils.base64ToBlobUrl(imageUrl);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保Blob URL有原始base64数据
|
||||||
|
if (displayUrl.startsWith('blob:') && !displayUrl._originalBase64 && originalUrl.startsWith('data:image/')) {
|
||||||
|
displayUrl._originalBase64 = originalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
imageDiv.innerHTML = `
|
imageDiv.innerHTML = `
|
||||||
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
||||||
@@ -935,7 +987,23 @@ const uiController = {
|
|||||||
placeholder.id = '';
|
placeholder.id = '';
|
||||||
|
|
||||||
// 确保imageUrl是Blob URL用于显示,但保存原始URL用于存储
|
// 确保imageUrl是Blob URL用于显示,但保存原始URL用于存储
|
||||||
const displayUrl = imageUrl.startsWith('blob:') ? imageUrl : utils.base64ToBlobUrl(imageUrl);
|
let displayUrl;
|
||||||
|
let originalUrl = imageUrl; // 原始URL,可能是base64或Blob URL
|
||||||
|
|
||||||
|
if (imageUrl.startsWith('blob:')) {
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
displayUrl = utils.base64ToBlobUrl(imageUrl);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保Blob URL有原始base64数据
|
||||||
|
if (displayUrl.startsWith('blob:') && !displayUrl._originalBase64 && originalUrl.startsWith('data:image/')) {
|
||||||
|
displayUrl._originalBase64 = originalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
placeholder.innerHTML = `
|
placeholder.innerHTML = `
|
||||||
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
||||||
@@ -1057,7 +1125,17 @@ const uiController = {
|
|||||||
currentImageIndex = generatedImages.findIndex(img => img.url === imageUrl);
|
currentImageIndex = generatedImages.findIndex(img => img.url === imageUrl);
|
||||||
|
|
||||||
// 设置图像源 - 确保正确处理base64和Blob URL
|
// 设置图像源 - 确保正确处理base64和Blob URL
|
||||||
const displayUrl = imageUrl.startsWith('blob:') ? imageUrl : utils.base64ToBlobUrl(imageUrl);
|
let displayUrl;
|
||||||
|
if (imageUrl.startsWith('blob:')) {
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
displayUrl = utils.base64ToBlobUrl(imageUrl);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
modalImage.src = displayUrl;
|
modalImage.src = displayUrl;
|
||||||
modalImage.onerror = function() {
|
modalImage.onerror = function() {
|
||||||
utils.showNotification('图像加载失败', 'danger');
|
utils.showNotification('图像加载失败', 'danger');
|
||||||
@@ -1066,7 +1144,7 @@ const uiController = {
|
|||||||
// 设置下载按钮功能
|
// 设置下载按钮功能
|
||||||
if (downloadButton) {
|
if (downloadButton) {
|
||||||
downloadButton.onclick = function() {
|
downloadButton.onclick = function() {
|
||||||
app.downloadImage(imageUrl);
|
app.downloadImage(generatedImages[currentImageIndex].url);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,7 +1164,10 @@ const uiController = {
|
|||||||
|
|
||||||
// 重新加载当前图像
|
// 重新加载当前图像
|
||||||
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
modalImage.src = generatedImages[currentImageIndex].url;
|
const displayUrl = generatedImages[currentImageIndex].url.startsWith('blob:') ?
|
||||||
|
generatedImages[currentImageIndex].url :
|
||||||
|
utils.base64ToBlobUrl(generatedImages[currentImageIndex].url);
|
||||||
|
modalImage.src = displayUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateNavigationButtons();
|
this.updateNavigationButtons();
|
||||||
@@ -1285,12 +1366,21 @@ const uiController = {
|
|||||||
// 更新图片
|
// 更新图片
|
||||||
const modalImage = document.getElementById('viewerModalImage');
|
const modalImage = document.getElementById('viewerModalImage');
|
||||||
const deleteButton = document.getElementById('viewerDeleteImage');
|
const deleteButton = document.getElementById('viewerDeleteImage');
|
||||||
|
const downloadButton = document.getElementById('viewerDownloadImage');
|
||||||
|
|
||||||
if (modalImage && generatedImages[currentImageIndex]) {
|
if (modalImage && generatedImages[currentImageIndex]) {
|
||||||
// 确保正确处理base64和Blob URL
|
// 确保正确处理base64和Blob URL
|
||||||
const displayUrl = generatedImages[currentImageIndex].url.startsWith('blob:') ?
|
const imageUrl = generatedImages[currentImageIndex].url;
|
||||||
generatedImages[currentImageIndex].url :
|
let displayUrl;
|
||||||
utils.base64ToBlobUrl(generatedImages[currentImageIndex].url);
|
if (imageUrl.startsWith('blob:')) {
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
displayUrl = utils.base64ToBlobUrl(imageUrl);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
displayUrl = imageUrl;
|
||||||
|
}
|
||||||
modalImage.src = displayUrl;
|
modalImage.src = displayUrl;
|
||||||
|
|
||||||
// 更新删除按钮对应的图像ID
|
// 更新删除按钮对应的图像ID
|
||||||
@@ -1306,9 +1396,17 @@ const uiController = {
|
|||||||
currentImageIndex = generatedImages.length - 1;
|
currentImageIndex = generatedImages.length - 1;
|
||||||
}
|
}
|
||||||
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
const newDisplayUrl = generatedImages[currentImageIndex].url.startsWith('blob:') ?
|
const imageUrl = generatedImages[currentImageIndex].url;
|
||||||
generatedImages[currentImageIndex].url :
|
let newDisplayUrl;
|
||||||
utils.base64ToBlobUrl(generatedImages[currentImageIndex].url);
|
if (imageUrl.startsWith('blob:')) {
|
||||||
|
newDisplayUrl = imageUrl;
|
||||||
|
} else if (imageUrl.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
newDisplayUrl = utils.base64ToBlobUrl(imageUrl);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
newDisplayUrl = imageUrl;
|
||||||
|
}
|
||||||
modalImage.src = newDisplayUrl;
|
modalImage.src = newDisplayUrl;
|
||||||
deleteButton.onclick = arguments.callee;
|
deleteButton.onclick = arguments.callee;
|
||||||
}
|
}
|
||||||
@@ -1316,6 +1414,13 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新下载按钮对应的图像URL
|
||||||
|
if (downloadButton) {
|
||||||
|
downloadButton.onclick = function() {
|
||||||
|
app.downloadImage(generatedImages[currentImageIndex].url);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新导航按钮状态
|
// 更新导航按钮状态
|
||||||
@@ -1382,7 +1487,16 @@ const uiController = {
|
|||||||
const preview = document.getElementById('imagePreview');
|
const preview = document.getElementById('imagePreview');
|
||||||
|
|
||||||
// 确保图像数据是Blob URL用于显示,但保持原始数据用于其他操作
|
// 确保图像数据是Blob URL用于显示,但保持原始数据用于其他操作
|
||||||
const displayUrl = imageData.data.startsWith('blob:') ? imageData.data : utils.base64ToBlobUrl(imageData.data);
|
let displayUrl;
|
||||||
|
if (imageData.data.startsWith('blob:')) {
|
||||||
|
displayUrl = imageData.data;
|
||||||
|
} else if (imageData.data.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据,转换为Blob URL
|
||||||
|
displayUrl = utils.base64ToBlobUrl(imageData.data);
|
||||||
|
} else {
|
||||||
|
// 其他格式,直接使用
|
||||||
|
displayUrl = imageData.data;
|
||||||
|
}
|
||||||
|
|
||||||
preview.innerHTML = `
|
preview.innerHTML = `
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
@@ -1508,8 +1622,16 @@ const uiController = {
|
|||||||
const imageDiv = document.createElement('div');
|
const imageDiv = document.createElement('div');
|
||||||
imageDiv.className = 'image-item fade-in';
|
imageDiv.className = 'image-item fade-in';
|
||||||
|
|
||||||
// 确保从IndexedDB加载的base64数据转换为Blob URL用于显示
|
// 从IndexedDB加载的数据应该是base64格式,直接使用
|
||||||
const displayUrl = img.url.startsWith('blob:') ? img.url : utils.base64ToBlobUrl(img.url);
|
// 如果是base64数据,创建一个新的Blob URL用于显示
|
||||||
|
let displayUrl;
|
||||||
|
if (img.url.startsWith('data:image/')) {
|
||||||
|
// 这是base64数据
|
||||||
|
displayUrl = utils.base64ToBlobUrl(img.url);
|
||||||
|
} else {
|
||||||
|
// 这可能是其他格式的URL,直接使用
|
||||||
|
displayUrl = img.url;
|
||||||
|
}
|
||||||
|
|
||||||
imageDiv.innerHTML = `
|
imageDiv.innerHTML = `
|
||||||
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
<img src="${displayUrl}" alt="Generated Image" loading="lazy" class="generated-image">
|
||||||
@@ -1881,7 +2003,13 @@ const app = {
|
|||||||
|
|
||||||
// 为每个图像添加新的图像项
|
// 为每个图像添加新的图像项
|
||||||
result.response.images.forEach((img, imgIndex) => {
|
result.response.images.forEach((img, imgIndex) => {
|
||||||
uiController.addGeneratedImage(img);
|
// 确保Blob URL有原始base64数据
|
||||||
|
if (img.startsWith('blob:') && img._originalBase64) {
|
||||||
|
uiController.addGeneratedImage(img);
|
||||||
|
} else {
|
||||||
|
// 如果没有原始base64数据,需要从API响应中获取
|
||||||
|
uiController.addGeneratedImage(img);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 只有一个图像,直接替换占位符
|
// 只有一个图像,直接替换占位符
|
||||||
@@ -2035,7 +2163,7 @@ const app = {
|
|||||||
utils.showNotification('下载图像失败', 'danger');
|
utils.showNotification('下载图像失败', 'danger');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 如果是普通URL,直接下载
|
// 如果是base64数据,直接下载
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.href = imageUrl;
|
link.href = imageUrl;
|
||||||
link.download = `generated-image-${Date.now()}.png`;
|
link.download = `generated-image-${Date.now()}.png`;
|
||||||
@@ -2056,10 +2184,37 @@ const app = {
|
|||||||
// 逐个下载图像
|
// 逐个下载图像
|
||||||
generatedImages.forEach((img, index) => {
|
generatedImages.forEach((img, index) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const link = document.createElement('a');
|
// 使用与单个图像下载相同的逻辑
|
||||||
link.href = img.url;
|
if (img.url.startsWith('blob:') && img.url._originalBase64) {
|
||||||
link.download = `generated-image-${Date.now()}-${index + 1}.png`;
|
// 使用原始base64数据下载
|
||||||
link.click();
|
const link = document.createElement('a');
|
||||||
|
link.href = img.url._originalBase64;
|
||||||
|
link.download = `generated-image-${Date.now()}-${index + 1}.png`;
|
||||||
|
link.click();
|
||||||
|
} else if (img.url.startsWith('blob:')) {
|
||||||
|
// 如果没有原始base64数据,通过fetch获取Blob数据
|
||||||
|
fetch(img.url)
|
||||||
|
.then(response => response.blob())
|
||||||
|
.then(blob => {
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.download = `generated-image-${Date.now()}-${index + 1}.png`;
|
||||||
|
link.click();
|
||||||
|
// 清理临时URL
|
||||||
|
setTimeout(() => URL.revokeObjectURL(url), 100);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error downloading image:', error);
|
||||||
|
utils.showNotification('下载图像失败', 'danger');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 如果是base64数据,直接下载
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = img.url;
|
||||||
|
link.download = `generated-image-${Date.now()}-${index + 1}.png`;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
|
|
||||||
// 最后一个图像下载完成后显示通知
|
// 最后一个图像下载完成后显示通知
|
||||||
if (index === generatedImages.length - 1) {
|
if (index === generatedImages.length - 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user