Update script.js
This commit is contained in:
parent
4b964a20b8
commit
19517c3166
1 changed files with 125 additions and 1 deletions
126
static/script.js
126
static/script.js
|
|
@ -404,6 +404,129 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const TEMPLATE_TAG_LIMIT = 8;
|
const TEMPLATE_TAG_LIMIT = 8;
|
||||||
let templateTags = [];
|
let templateTags = [];
|
||||||
|
|
||||||
|
const TEMPLATE_PREVIEW_MAX_DIMENSION = 1024;
|
||||||
|
const TEMPLATE_PREVIEW_QUALITY = 0.85;
|
||||||
|
|
||||||
|
function getExtensionFromMime(mime) {
|
||||||
|
if (!mime) return 'png';
|
||||||
|
const normalized = mime.toLowerCase();
|
||||||
|
if (normalized.includes('jpeg') || normalized.includes('jpg')) {
|
||||||
|
return 'jpg';
|
||||||
|
}
|
||||||
|
if (normalized.includes('webp')) {
|
||||||
|
return 'webp';
|
||||||
|
}
|
||||||
|
if (normalized.includes('png')) {
|
||||||
|
return 'png';
|
||||||
|
}
|
||||||
|
return 'png';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensurePreviewFileName(original, mimeType) {
|
||||||
|
const baseName = (original || 'preview').replace(/\.[^.]+$/, '');
|
||||||
|
const extension = getExtensionFromMime(mimeType);
|
||||||
|
return `${baseName}.${extension}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadImageFromFile(file) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const objectUrl = URL.createObjectURL(file);
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
URL.revokeObjectURL(objectUrl);
|
||||||
|
resolve(img);
|
||||||
|
};
|
||||||
|
img.onerror = (err) => {
|
||||||
|
URL.revokeObjectURL(objectUrl);
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
img.src = objectUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getImageBitmapFromFile(file) {
|
||||||
|
if (window.createImageBitmap) {
|
||||||
|
try {
|
||||||
|
return await createImageBitmap(file);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('createImageBitmap failed, falling back to Image element', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loadImageFromFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function canvasToBlob(canvas, type, quality) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
if (blob) {
|
||||||
|
resolve(blob);
|
||||||
|
} else {
|
||||||
|
reject(new Error('Canvas toBlob returned null'));
|
||||||
|
}
|
||||||
|
}, type, quality);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function compressPreviewFileForUpload(file) {
|
||||||
|
if (!file || !file.type || !file.type.startsWith('image/')) {
|
||||||
|
return { blob: file, filename: file?.name || 'preview.png' };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const bitmap = await getImageBitmapFromFile(file);
|
||||||
|
const bitmapWidth = typeof bitmap.width === 'number' && bitmap.width > 0 ? bitmap.width : (bitmap.naturalWidth || 0);
|
||||||
|
const bitmapHeight = typeof bitmap.height === 'number' && bitmap.height > 0 ? bitmap.height : (bitmap.naturalHeight || 0);
|
||||||
|
if (!bitmapWidth || !bitmapHeight) {
|
||||||
|
throw new Error('Invalid image dimensions');
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxSide = Math.max(bitmapWidth, bitmapHeight);
|
||||||
|
const scale = maxSide > TEMPLATE_PREVIEW_MAX_DIMENSION ? TEMPLATE_PREVIEW_MAX_DIMENSION / maxSide : 1;
|
||||||
|
const targetWidth = Math.max(1, Math.round(bitmapWidth * scale));
|
||||||
|
const targetHeight = Math.max(1, Math.round(bitmapHeight * scale));
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = targetWidth;
|
||||||
|
canvas.height = targetHeight;
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error('Unable to create canvas context');
|
||||||
|
}
|
||||||
|
ctx.imageSmoothingEnabled = true;
|
||||||
|
ctx.imageSmoothingQuality = 'high';
|
||||||
|
ctx.drawImage(bitmap, 0, 0, targetWidth, targetHeight);
|
||||||
|
|
||||||
|
if (bitmap.close) {
|
||||||
|
bitmap.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetType = file.type.toLowerCase();
|
||||||
|
if (!targetType.startsWith('image/')) {
|
||||||
|
targetType = 'image/png';
|
||||||
|
}
|
||||||
|
|
||||||
|
let blob;
|
||||||
|
const quality = targetType === 'image/png' ? undefined : TEMPLATE_PREVIEW_QUALITY;
|
||||||
|
try {
|
||||||
|
blob = await canvasToBlob(canvas, targetType, quality);
|
||||||
|
} catch (error) {
|
||||||
|
if (targetType !== 'image/png') {
|
||||||
|
targetType = 'image/png';
|
||||||
|
blob = await canvasToBlob(canvas, targetType);
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = ensurePreviewFileName(file.name, targetType);
|
||||||
|
return { blob, filename };
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Failed to compress template preview, falling back to original file', error);
|
||||||
|
return { blob: file, filename: file.name || 'preview.png' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeRawTags(raw) {
|
function normalizeRawTags(raw) {
|
||||||
if (!raw) return [];
|
if (!raw) return [];
|
||||||
if (Array.isArray(raw)) {
|
if (Array.isArray(raw)) {
|
||||||
|
|
@ -880,7 +1003,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
formData.append('tags', JSON.stringify(templateTags));
|
formData.append('tags', JSON.stringify(templateTags));
|
||||||
|
|
||||||
if (currentPreviewFile) {
|
if (currentPreviewFile) {
|
||||||
formData.append('preview', currentPreviewFile);
|
const previewPayload = await compressPreviewFileForUpload(currentPreviewFile);
|
||||||
|
formData.append('preview', previewPayload.blob, previewPayload.filename);
|
||||||
} else if (currentPreviewUrl) {
|
} else if (currentPreviewUrl) {
|
||||||
formData.append('preview_path', currentPreviewUrl);
|
formData.append('preview_path', currentPreviewUrl);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue