add basic files

This commit is contained in:
Julian Freeman
2025-06-26 13:54:35 -04:00
parent efdd76d11e
commit e6b7c8d34d
5 changed files with 521 additions and 0 deletions

340
templates/index.html Normal file
View File

@@ -0,0 +1,340 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>图像处理工具集</title>
<link rel="icon" href="/static/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<style>
body {
font-family: "Segoe UI", sans-serif;
background: linear-gradient(to right, #f0f2f5, #dfe4ea);
padding: 40px;
}
.container {
max-width: 600px;
margin: auto;
background: white;
padding: 30px 40px;
border-radius: 16px;
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08);
animation: fadeIn 0.8s ease-in-out;
margin-bottom: 30px; /* 增加卡片之间的间隙 */
}
.logo {
text-align: center;
font-size: 28px;
color: #4a90e2;
margin-bottom: 20px;
}
.logo i {
margin-right: 10px;
}
h2 {
text-align: center;
font-size: 22px;
margin-bottom: 12px;
}
.notice {
font-size: 14px;
color: #666;
margin-bottom: 18px;
text-align: center;
}
.drop-zone {
border: 2px dashed #ccc;
border-radius: 12px;
padding: 30px;
text-align: center;
color: #888;
cursor: pointer;
margin-bottom: 16px;
transition: all 0.3s ease;
}
.drop-zone.dragover {
background: #eef6ff;
border-color: #4a90e2;
color: #4a90e2;
}
.drop-zone i {
font-size: 36px;
margin-bottom: 10px;
display: block;
color: #bbb;
}
button {
background-color: #4a90e2;
color: white;
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: background-color 0.3s, transform 0.2s;
}
button:hover {
background-color: #357abd;
transform: scale(1.02);
}
.progress-container {
margin-top: 15px;
height: 12px;
background: #e0e0e0;
border-radius: 8px;
overflow: hidden;
display: none;
}
.progress-bar {
width: 0%;
height: 100%;
background-color: #4a90e2;
transition: width 0.3s ease;
}
.spinner {
text-align: center;
font-size: 15px;
color: #555;
margin-top: 12px;
display: none;
}
.spinner i {
margin-right: 6px;
}
.download-link {
margin-top: 20px;
text-align: center;
font-size: 16px;
}
.download-link i {
margin-right: 6px;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<div class="container">
<div class="logo">
<i class="fas fa-image"></i> 边框背景图像调整尺寸
</div>
<h2>将不同比例的边框图片调整为 800x1000 尺寸</h2>
<p class="notice">支持批量上传 PNG / JPG / WebP 图片,推荐使用竖图(比例 9:16 或 3:4</p>
<div class="drop-zone" id="dropZone" title="支持拖拽上传图片或点击选择文件">
<i class="fas fa-cloud-upload-alt"></i>
拖拽图片到这里,或点击选择
</div>
<form id="uploadForm" enctype="multipart/form-data" style="display: none;">
<input type="file" id="fileInput" name="files" multiple accept="image/png, image/jpeg, image/webp">
</form>
<div class="progress-container" id="progressContainer">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="spinner" id="loadingSpinner">
<i class="fas fa-circle-notch fa-spin"></i> 正在处理,请稍候...
</div>
<div class="download-link" id="result"></div>
</div>
<div class="container">
<div class="logo">
<i class="fas fa-image"></i> 图像背景移除
</div>
<h2>批量移除图片背景</h2>
<p class="notice">支持批量上传 PNG / JPG 图片,移除背景后可下载结果</p>
<div class="drop-zone" id="bgRemoveDropZone" title="支持拖拽上传图片或点击选择文件">
<i class="fas fa-cloud-upload-alt"></i>
拖拽图片到这里,或点击选择
</div>
<form id="bgRemoveForm" enctype="multipart/form-data" style="display: none;">
<input type="file" id="bgRemoveFileInput" name="files" multiple accept="image/png, image/jpeg">
</form>
<div class="progress-container" id="bgRemoveProgressContainer">
<div class="progress-bar" id="bgRemoveProgressBar"></div>
</div>
<div class="spinner" id="bgRemoveLoadingSpinner">
<i class="fas fa-circle-notch fa-spin"></i> 正在处理,请稍候...
</div>
<div class="download-link" id="bgRemoveResult"></div>
</div>
<script>
const dropZone = document.getElementById("dropZone");
const fileInput = document.getElementById("fileInput");
const progressBar = document.getElementById("progressBar");
const progressContainer = document.getElementById("progressContainer");
const resultBox = document.getElementById("result");
const spinner = document.getElementById("loadingSpinner");
dropZone.addEventListener("click", () => fileInput.click());
dropZone.addEventListener("dragover", e => {
e.preventDefault();
dropZone.classList.add("dragover");
});
dropZone.addEventListener("dragleave", () => {
dropZone.classList.remove("dragover");
});
dropZone.addEventListener("drop", e => {
e.preventDefault();
dropZone.classList.remove("dragover");
fileInput.files = e.dataTransfer.files;
uploadFiles(fileInput.files);
});
fileInput.addEventListener("change", () => {
if (fileInput.files.length > 0) {
uploadFiles(fileInput.files);
}
});
async function uploadFiles(files) {
resultBox.innerHTML = "";
progressBar.style.width = "0%";
progressContainer.style.display = "block";
spinner.style.display = "block";
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("files", files[i]);
}
const xhr = new XMLHttpRequest();
xhr.open("POST", "/upload", true);
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
progressBar.style.width = percent + "%";
}
};
xhr.onload = function () {
spinner.style.display = "none";
progressContainer.style.display = "none";
if (xhr.status === 200) {
const res = JSON.parse(xhr.responseText);
if (res.download_url) {
resultBox.innerHTML = `<i class="fas fa-check-circle" style="color:green;"></i> <a href='${res.download_url}' download>点击下载处理结果</a>`;
} else {
resultBox.innerHTML = `<i class="fas fa-times-circle" style="color:red;"></i> 上传失败,请检查文件格式。`;
}
} else {
resultBox.innerHTML = `<i class="fas fa-exclamation-circle" style="color:orange;"></i> 上传错误,请稍后重试。`;
}
};
xhr.send(formData);
}
const bgRemoveDropZone = document.getElementById("bgRemoveDropZone");
const bgRemoveFileInput = document.getElementById("bgRemoveFileInput");
const bgRemoveProgressBar = document.getElementById("bgRemoveProgressBar");
const bgRemoveProgressContainer = document.getElementById("bgRemoveProgressContainer");
const bgRemoveResultBox = document.getElementById("bgRemoveResult");
const bgRemoveSpinner = document.getElementById("bgRemoveLoadingSpinner");
bgRemoveDropZone.addEventListener("click", () => bgRemoveFileInput.click());
bgRemoveDropZone.addEventListener("dragover", e => {
e.preventDefault();
bgRemoveDropZone.classList.add("dragover");
});
bgRemoveDropZone.addEventListener("dragleave", () => {
bgRemoveDropZone.classList.remove("dragover");
});
bgRemoveDropZone.addEventListener("drop", e => {
e.preventDefault();
bgRemoveDropZone.classList.remove("dragover");
bgRemoveFileInput.files = e.dataTransfer.files;
uploadBgRemoveFiles(bgRemoveFileInput.files);
});
bgRemoveFileInput.addEventListener("change", () => {
if (bgRemoveFileInput.files.length > 0) {
uploadBgRemoveFiles(bgRemoveFileInput.files);
}
});
async function uploadBgRemoveFiles(files) {
bgRemoveResultBox.innerHTML = "";
bgRemoveProgressBar.style.width = "0%";
bgRemoveProgressContainer.style.display = "block";
bgRemoveSpinner.style.display = "block";
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
formData.append("files", files[i]);
}
const xhr = new XMLHttpRequest();
xhr.open("POST", "/remove-bg", true);
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
const percent = Math.round((e.loaded / e.total) * 100);
bgRemoveProgressBar.style.width = percent + "%";
}
};
xhr.onload = function () {
bgRemoveSpinner.style.display = "none";
bgRemoveProgressContainer.style.display = "none";
if (xhr.status === 200) {
const res = JSON.parse(xhr.responseText);
if (res.download_url) {
bgRemoveResultBox.innerHTML = `<i class="fas fa-check-circle" style="color:green;"></i> <a href='${res.download_url}' download>点击下载处理结果</a>`;
} else {
bgRemoveResultBox.innerHTML = `<i class="fas fa-times-circle" style="color:red;"></i> 上传失败,请检查文件格式。`;
}
} else {
bgRemoveResultBox.innerHTML = `<i class="fas fa-exclamation-circle" style="color:orange;"></i> 上传错误,请稍后重试。`;
}
};
xhr.send(formData);
}
</script>
</body>
</html>