Files
trpic/web/scripts/convert/convert.js
2026-04-22 21:19:50 +08:00

404 lines
12 KiB
JavaScript

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})`;
}
});