class MetaParser { static parse() { let file; const metas = document.querySelectorAll("meta[name]"); metas.forEach(meta => { const name = meta.getAttribute("name"); const data = this.metaToObject(meta); if (name === "file") { file = data; } }); return file; } static metaToObject(meta) { const obj = {}; for (const attr of meta.attributes) { let value = attr.value; if (value === "true") { value = true; } else if (value === "false") { value = false; } else if (Number.isSafeInteger(value) && !isNaN(value) && value.trim() !== "") { value = Number(value); } obj[attr.name] = value; } return obj; } } document.addEventListener('DOMContentLoaded', () => { let file = MetaParser.parse(), currentScale = 1.0, maxScale = 16, minScale = 0.5, isDragging = false, hasMoved = false, downX = 0, downY = 0, startX = 0, startY = 0, currentX = 0, currentY = 0, requesting = false; let qualitySelector = document.getElementById("quality-selector"); qualitySelector.addEventListener("change", switchQuality.bind(this)); let convertButton = document.getElementById("convert-button"); convertButton.addEventListener("click", sendConvertRequest.bind(this)); let saveButton = document.getElementById("save-button"); saveButton.addEventListener("click", convertDraftDone.bind(this)); let resetButton = document.getElementById("reset-button"); resetButton.addEventListener("click", resetImage.bind(this)); let preview = document.getElementById("preview"); preview.style.display = "block"; let previewHeader = document.getElementById("preview-header"); let previewView = document.getElementById("preview-view"); previewView.addEventListener("wheel", handleWheel.bind(this)); previewView.addEventListener("mousedown", startDrag.bind(this)); let imageWrapper = document.getElementById("image-wrapper"); let previewImg = document.getElementById("preview-img"); let originalImg = document.getElementById("original-img"); originalImg.addEventListener("error", collectRaw.bind(this)); let originalSize = document.getElementById("original-size"); if (originalSize.textContent == "") { collectRaw(); } else { originalImg.src = `/files/${file.id_str}.${file.filename.split(".")[1]}`; } let denoiseSelector = document.getElementById("denoise-selector"); denoiseSelector.addEventListener("change", switchDeNoiseLevel.bind(this)); let denoiseButton = document.getElementById("denoise-button"); denoiseButton.addEventListener("click", sendDeNoiseRequest.bind(this)); function switchDeNoiseLevel() { level = denoiseSelector.value; let element = document.getElementById("l" + level); if (element.dataset.converted) { previewImg.src = `/files/${file.id_str}_l${level}.png`; previewImg.style.opacity = 1 previewHeader.style.backgroundColor = "#333" } } function sendDeNoiseRequest() { if (requesting) { alert("Image is converting"); return; } level = denoiseSelector.value; let element = document.getElementById("l" + level); if (element.dataset.converted) { alert(`Image already denoise with ${level} level`); return; } requesting = true; denoiseButton.textContent = "denoising" denoiseButton.style.backgroundColor = "rgb(50, 80, 80)"; fetch(`/api/task/files/denoise-draft/${file.id_str}/${level}`) .then(response => { response.json().then((resjson) => { switch (response.status) { case 200: element.dataset.converted = true; element.textContent += ` - ok`; previewImg.src = `/files/${file.id_str}_l${level}.png`; break; default: alert(`转换发生错误:${resjson.msg}: ${resjson.error}`); } }); }) .finally(() => { denoiseButton.textContent = "denoise" denoiseButton.style.backgroundColor = "#444"; requesting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } function switchQuality() { quality = qualitySelector.value; let element = document.getElementById("q" + quality); if (element.dataset.converted) { previewImg.src = `/files/${file.id_str}_q${quality}.webp`; previewImg.style.opacity = 1 previewHeader.style.backgroundColor = "#333" } } function sendConvertRequest() { if (requesting) { alert("Image is converting"); return; } quality = qualitySelector.value; let element = document.getElementById("q" + quality); if (element.dataset.converted) { alert(`Image already converted with ${quality}% quality`); return; } else if (element.dataset.oversize) { alert(`Image is too large to convert with ${quality}% quality`); return; } requesting = true; convertButton.textContent = "converting" convertButton.style.backgroundColor = "rgb(50, 80, 80)"; fetch(`/api/task/files/convert-draft/webp/${file.id_str}/${quality}`) .then(response => { response.json().then((resjson) => { switch (response.status) { case 200: element.dataset.converted = true; element.textContent += ` - ${resjson.size_str_converted}`; previewImg.src = `/files/${file.id_str}_q${quality}.webp`; break; case 417: element.dataset.oversize = true; element.textContent += ` - oversize`; alert(`Image converted size bigger than original size, cancelled`) break; default: alert(`转换发生错误:${resjson.msg}: ${resjson.error}`); } }); }) .finally(() => { convertButton.textContent = "convert" convertButton.style.backgroundColor = "#444"; requesting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } function convertDraftDone() { if (requesting) { alert("Request is already in progress"); return; } quality = qualitySelector.value; requesting = true; saveButton.textContent = "saving" saveButton.style.backgroundColor = "rgb(50, 80, 80)"; fetch(`/api/task/files/convert-draft-done/webp/${file.id_str}/${quality}`) .then(response => { response.json().then((resjson) => { switch (response.status) { case 200: break; default: alert(`发生错误:${resjson.msg}: ${resjson.error}`); } }); }) .finally(() => { saveButton.textContent = "saved" saveButton.style.backgroundColor = "#444"; requesting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } function resetImage() { if (requesting) { alert("another request is already in progress"); return; } requesting = true; resetButton.textContent = "resetting" resetButton.style.backgroundColor = "rgb(50, 80, 80)"; fetch(`/api/task/files/convert-reset/${file.id_str}`) .then(response => { response.json().then((resjson) => { switch (response.status) { case 200: break; default: alert(`发生错误:${resjson.msg}: ${resjson.error}`); } }); }) .finally(() => { resetButton.textContent = "reset" resetButton.style.backgroundColor = "#444"; requesting = false; }) .catch(error => { alert(`请求失败: ${error}`); }); } function collectRaw() { if (confirm(`The original image could not be loaded. Need try download it to the server?`)) { fetch(`/api/task/files/convert-raw/${file.id_str}`) .then(response => { response.json().then((resjson) => { switch (response.status) { case 200: originalImg.src = resjson.url; originalSize.textContent = resjson.size_str; break; default: alert(`发生错误:${resjson.msg}: ${resjson.error}`); return } }); }) .catch(error => { alert(`请求失败: ${error}`); }); } } document.addEventListener('keydown', (e) => { if (e.ctrlKey) { previewImg.style.opacity = 0 previewHeader.style.display = "none" } switch (e.key) { case 'ArrowDown': e.preventDefault(); if (qualitySelector.value <= 35) return; qualitySelector.value = String(Number(qualitySelector.value) - 5) switchQuality(); break; case 'ArrowUp': e.preventDefault(); if (qualitySelector.value >= 90) return; qualitySelector.value = String(Number(qualitySelector.value) + 5) switchQuality(); break; } }); document.addEventListener('keyup', (e) => { if (e.key === 'Control') { previewImg.style.opacity = 1 previewHeader.style.display = "flex" } }); function handleWheel(e) { e.preventDefault(); const step = currentScale >= 4 ? 0.4 : currentScale >= 2 ? 0.2 : 0.1; const delta = e.deltaY > 0 ? -step : step; const newScale = parseFloat((currentScale + delta).toFixed(10)); if (newScale >= minScale && newScale <= maxScale) { const ratio = newScale / currentScale; const rect = previewView.getBoundingClientRect(); const offsetX = e.clientX - (rect.left + rect.width / 2); const offsetY = e.clientY - (rect.top + rect.height / 2); currentX = offsetX * (1 - ratio) + currentX * ratio; currentY = offsetY * (1 - ratio) + currentY * ratio; currentScale = newScale; updateImageTransform(); } } function startDrag(e) { if (e.button !== 0) return; e.preventDefault(); e.stopPropagation(); isDragging = true; hasMoved = false; startX = e.clientX - currentX; startY = e.clientY - currentY; downX = e.clientX; downY = e.clientY; imageWrapper.classList.add("dragging"); bindDragEvents(); } function doDrag(e) { if (!isDragging) return; e.preventDefault(); e.stopPropagation(); const dx = e.clientX - downX; const dy = e.clientY - downY; if (Math.abs(dx) > 2 || Math.abs(dy) > 2) { hasMoved = true; } currentX = e.clientX - startX; currentY = e.clientY - startY; updateImageTransform(); } function endDrag(e) { if (!isDragging) return; if (e) e.stopPropagation(); isDragging = false; imageWrapper.classList.remove("dragging"); unbindDragEvents(); if (!hasMoved) { previewImg.style.opacity = previewImg.style.opacity === "0" ? "1" : "0"; previewHeader.style.display = previewImg.style.opacity === "0" ? "none" : "flex"; } } function bindDragEvents() { previewView.addEventListener("mousemove", doDrag.bind(this)); previewView.addEventListener("mouseup", endDrag.bind(this)); previewView.addEventListener("mouseleave", endDrag.bind(this)); } function unbindDragEvents() { previewView.removeEventListener("mousemove", doDrag.bind(this)); previewView.removeEventListener("mouseup", endDrag.bind(this)); previewView.removeEventListener("mouseleave", endDrag.bind(this)); } function resetTransform() { currentScale = 1.0; currentX = 0; currentY = 0; updateImageTransform(); } function updateImageTransform() { imageWrapper.style.transform = `translate(${currentX}px, ${currentY}px) scale(${currentScale})`; } });