feat: ComfyUI 改走 10.60.74.221,测试页上传图超阈值自动降采样
将 worker 默认 ComfyUI 地址改为远端 10.60.74.221:8188;前端测试页在像素超过 1536000 时等比缩小到 786432 以内。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -598,7 +598,7 @@ _REPAINT_WORKFLOW = os.path.join(os.path.dirname(os.path.dirname(__file__)), "ha
|
|||||||
|
|
||||||
|
|
||||||
def _call_comfyui(image_bgr, mask_bool, prompt=None):
|
def _call_comfyui(image_bgr, mask_bool, prompt=None):
|
||||||
"""调本机 ComfyUI 的 Flux-2 inpaint 工作流(hair_repaint.json),返回与输入同分辨率的 BGR。
|
"""调远端 ComfyUI 的 Flux-2 inpaint 工作流(hair_repaint.json),返回与输入同分辨率的 BGR。
|
||||||
|
|
||||||
与 swapHair 的区别:ComfyUI 把「原图 VAE 编码作 reference latent + ColorMatch」双重保色,
|
与 swapHair 的区别:ComfyUI 把「原图 VAE 编码作 reference latent + ColorMatch」双重保色,
|
||||||
天生不易染色;提示词自由可调(中文)。mask 经 RGBA alpha 通道传入(透明=重绘区)。
|
天生不易染色;提示词自由可调(中文)。mask 经 RGBA alpha 通道传入(透明=重绘区)。
|
||||||
@@ -606,10 +606,10 @@ def _call_comfyui(image_bgr, mask_bool, prompt=None):
|
|||||||
"""
|
"""
|
||||||
import io
|
import io
|
||||||
from hairline.mask import compose_comfy_rgba
|
from hairline.mask import compose_comfy_rgba
|
||||||
from hairline.comfyui import run as comfyui_run, ping
|
from hairline.comfyui import COMFYUI_URL, run as comfyui_run, ping
|
||||||
|
|
||||||
if not ping():
|
if not ping():
|
||||||
raise SwapError("ComfyUI 不可达(http://127.0.0.1:8188),redraw Flux-2 路跳过")
|
raise SwapError(f"ComfyUI 不可达({COMFYUI_URL}),redraw Flux-2 路跳过")
|
||||||
mask_u8 = (mask_bool.astype(np.uint8)) * 255
|
mask_u8 = (mask_bool.astype(np.uint8)) * 255
|
||||||
rgba_img = compose_comfy_rgba(image_bgr, mask_u8) # alpha=255-mask:透明=重绘区
|
rgba_img = compose_comfy_rgba(image_bgr, mask_u8) # alpha=255-mask:透明=重绘区
|
||||||
buf = io.BytesIO()
|
buf = io.BytesIO()
|
||||||
|
|||||||
+4
-3
@@ -1,8 +1,9 @@
|
|||||||
"""ComfyUI 客户端:用 add_hair.json / add_hair2.json 工作流跑生发图(Flux-2 inpaint)。
|
"""ComfyUI 客户端:用 add_hair.json / add_hair2.json 工作流跑生发图(Flux-2 inpaint)。
|
||||||
|
|
||||||
worker 不跑 Flux,只把「划线图 + 遮罩」的 RGBA 上传到本机 ComfyUI(默认 8188),
|
worker 不跑 Flux,只把「划线图 + 遮罩」的 RGBA 上传到远端 ComfyUI
|
||||||
|
(默认 http://10.60.74.221:8188,可用环境变量 COMFYUI_URL 覆盖),
|
||||||
替换工作流节点 26 的输入图、随机 seed,提交 /prompt,轮询 /history,取回 /view 输出。
|
替换工作流节点 26 的输入图、随机 seed,提交 /prompt,轮询 /history,取回 /view 输出。
|
||||||
ComfyUI 开启了 HTTP Basic Auth(user `admin` + 密码),所有请求都带凭据。
|
ComfyUI 若开启了 HTTP Basic Auth(user `admin` + 密码),所有请求都带凭据。
|
||||||
|
|
||||||
支持多工作流:run() 可通过 workflow_path 指定不同工作流 JSON,自动检测 SaveImage 输出节点。
|
支持多工作流:run() 可通过 workflow_path 指定不同工作流 JSON,自动检测 SaveImage 输出节点。
|
||||||
"""
|
"""
|
||||||
@@ -17,7 +18,7 @@ import uuid
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
COMFYUI_URL = os.getenv("COMFYUI_URL", "http://127.0.0.1:8188").rstrip("/")
|
COMFYUI_URL = os.getenv("COMFYUI_URL", "http://10.60.74.221:8188").rstrip("/")
|
||||||
_WORKFLOW_DEFAULT = os.getenv(
|
_WORKFLOW_DEFAULT = os.getenv(
|
||||||
"ADD_HAIR_WORKFLOW",
|
"ADD_HAIR_WORKFLOW",
|
||||||
os.path.join(os.path.dirname(os.path.dirname(__file__)), "add_hair.json"),
|
os.path.join(os.path.dirname(os.path.dirname(__file__)), "add_hair.json"),
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
// 上传图片自动降采样:当总像素 > MAX_PIXELS 时,等比例缩小到 <= TARGET_PIXELS。
|
||||||
|
// 用法:在提交前 file = await window.downscaleImageFile(file);
|
||||||
|
(function () {
|
||||||
|
var MAX_PIXELS = 1536000; // 触发阈值:超过则缩小
|
||||||
|
var TARGET_PIXELS = 786432; // 缩小后总像素上限
|
||||||
|
|
||||||
|
function loadImage(url) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function () { resolve(img); };
|
||||||
|
img.onerror = reject;
|
||||||
|
img.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function downscaleImageFile(file) {
|
||||||
|
// 非图片、GIF、SVG 不处理,原样返回
|
||||||
|
if (!file || !file.type || file.type.indexOf('image/') !== 0) return file;
|
||||||
|
if (file.type === 'image/gif' || file.type === 'image/svg+xml') return file;
|
||||||
|
|
||||||
|
var url = URL.createObjectURL(file);
|
||||||
|
try {
|
||||||
|
var img = await loadImage(url);
|
||||||
|
var w = img.naturalWidth, h = img.naturalHeight;
|
||||||
|
var total = w * h;
|
||||||
|
if (!total || total <= MAX_PIXELS) return file; // 未超阈值,原图直接用
|
||||||
|
|
||||||
|
var scale = Math.sqrt(TARGET_PIXELS / total);
|
||||||
|
var nw = Math.max(1, Math.round(w * scale));
|
||||||
|
var nh = Math.max(1, Math.round(h * scale));
|
||||||
|
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
canvas.width = nw;
|
||||||
|
canvas.height = nh;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0, nw, nh);
|
||||||
|
|
||||||
|
var outType = file.type === 'image/png' ? 'image/png' : 'image/jpeg';
|
||||||
|
var quality = outType === 'image/jpeg' ? 0.92 : undefined;
|
||||||
|
var blob = await new Promise(function (res) { canvas.toBlob(res, outType, quality); });
|
||||||
|
if (!blob) return file;
|
||||||
|
|
||||||
|
var base = (file.name || 'image').replace(/\.(jpe?g|png|webp|bmp)$/i, '');
|
||||||
|
var name = base + (outType === 'image/png' ? '.png' : '.jpg');
|
||||||
|
return new File([blob], name, { type: outType, lastModified: Date.now() });
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('downscaleImageFile 失败,使用原图', e);
|
||||||
|
return file;
|
||||||
|
} finally {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.downscaleImageFile = downscaleImageFile;
|
||||||
|
})();
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
@media (max-width: 768px) { .results { flex-direction: column; } }
|
@media (max-width: 768px) { .results { flex-direction: column; } }
|
||||||
.hidden { display: none !important; }
|
.hidden { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -127,8 +128,9 @@ function setStatus(text, type) {
|
|||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const fileInput = $('imageFile');
|
const fileInput = $('imageFile');
|
||||||
const file = fileInput.files[0];
|
let file = fileInput.files[0];
|
||||||
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const _reqStart = performance.now();
|
const _reqStart = performance.now();
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -197,8 +198,9 @@ function renderMetrics(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const btn = $('submitBtn');
|
const btn = $('submitBtn');
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -292,8 +293,9 @@ function renderResult(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const btn = $('submitBtn');
|
const btn = $('submitBtn');
|
||||||
btn.disabled = true; btn.textContent = '⏳ 请求中...';
|
btn.disabled = true; btn.textContent = '⏳ 请求中...';
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -287,8 +288,9 @@ function renderResult(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
// 页面隐藏但仍提交的固定默认值
|
// 页面隐藏但仍提交的固定默认值
|
||||||
const HIDDEN = {
|
const HIDDEN = {
|
||||||
seg_model: 'segformer',
|
seg_model: 'segformer',
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
.hidden { display: none; }
|
.hidden { display: none; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -243,8 +244,9 @@ function renderResult(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
// 页面隐藏但仍提交的固定默认值
|
// 页面隐藏但仍提交的固定默认值
|
||||||
const HIDDEN = {
|
const HIDDEN = {
|
||||||
seg_model: 'segformer',
|
seg_model: 'segformer',
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
.hidden { display: none; }
|
.hidden { display: none; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -131,8 +132,9 @@ function dataUriToBlob(dataUri) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const btn = $('submitBtn');
|
const btn = $('submitBtn');
|
||||||
btn.disabled = true; btn.textContent = '⏳ 生成中...';
|
btn.disabled = true; btn.textContent = '⏳ 生成中...';
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
.hidden { display: none; }
|
.hidden { display: none; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -100,8 +101,9 @@ function renderResult(d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const btn = $('submitBtn');
|
const btn = $('submitBtn');
|
||||||
btn.disabled = true; btn.textContent = '⏳ 重绘中...';
|
btn.disabled = true; btn.textContent = '⏳ 重绘中...';
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
|
|
||||||
.hidden { display: none !important; }
|
.hidden { display: none !important; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -140,9 +141,9 @@ function $(id) { return document.getElementById(id); }
|
|||||||
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const f = $('imageFile').files[0];
|
let f = $('imageFile').files[0];
|
||||||
if (!f) { setStatus('请选择图片', 'error'); return; }
|
if (!f) { setStatus('请选择图片', 'error'); return; }
|
||||||
|
f = await window.downscaleImageFile(f);
|
||||||
|
|
||||||
_origUrl = URL.createObjectURL(f);
|
_origUrl = URL.createObjectURL(f);
|
||||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 请求中...';
|
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 请求中...';
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
@media (max-width: 800px) { .results-layout, .preview-row { flex-direction: column; } }
|
@media (max-width: 800px) { .results-layout, .preview-row { flex-direction: column; } }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -139,9 +140,9 @@ function $(id) { return document.getElementById(id); }
|
|||||||
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const mf = $('markedFile').files[0];
|
let mf = $('markedFile').files[0];
|
||||||
if (!mf) { setStatus('请选择划线图', 'error'); return; }
|
if (!mf) { setStatus('请选择划线图', 'error'); return; }
|
||||||
|
mf = await window.downscaleImageFile(mf);
|
||||||
|
|
||||||
const markedUrl = URL.createObjectURL(mf);
|
const markedUrl = URL.createObjectURL(mf);
|
||||||
// 先显示原图
|
// 先显示原图
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
@media (max-width: 800px) { .results-layout { flex-direction: column; } }
|
@media (max-width: 800px) { .results-layout { flex-direction: column; } }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -121,8 +122,9 @@ function $(id) { return document.getElementById(id); }
|
|||||||
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const f = $('imageFile').files[0];
|
let f = $('imageFile').files[0];
|
||||||
if (!f) { setStatus('请选择图片', 'error'); return; }
|
if (!f) { setStatus('请选择图片', 'error'); return; }
|
||||||
|
f = await window.downscaleImageFile(f);
|
||||||
|
|
||||||
$('imgPreview').innerHTML = '<img src="'+URL.createObjectURL(f)+'" alt="preview">';
|
$('imgPreview').innerHTML = '<img src="'+URL.createObjectURL(f)+'" alt="preview">';
|
||||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 分析中...';
|
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 分析中...';
|
||||||
|
|||||||
@@ -88,6 +88,7 @@
|
|||||||
.hidden { display: none !important; }
|
.hidden { display: none !important; }
|
||||||
@media (max-width: 800px) { .results-layout { flex-direction: column; } }
|
@media (max-width: 800px) { .results-layout { flex-direction: column; } }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -195,10 +196,11 @@ function selectAllHair(select) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const f = $('imageFile').files[0];
|
let f = $('imageFile').files[0];
|
||||||
if (!f) { setStatus('请选择图片', 'error'); return; }
|
if (!f) { setStatus('请选择图片', 'error'); return; }
|
||||||
const checked = [...document.querySelectorAll('#hairStyleGroup input:checked')].map(cb => cb.value);
|
const checked = [...document.querySelectorAll('#hairStyleGroup input:checked')].map(cb => cb.value);
|
||||||
if (!checked.length) { setStatus('请至少选择一个发型', 'error'); return; }
|
if (!checked.length) { setStatus('请至少选择一个发型', 'error'); return; }
|
||||||
|
f = await window.downscaleImageFile(f);
|
||||||
|
|
||||||
_origUrl = URL.createObjectURL(f);
|
_origUrl = URL.createObjectURL(f);
|
||||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ ...';
|
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ ...';
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
.diff-list { font-size: 12px; color: #6b7280; margin-top: 6px; line-height: 1.7; }
|
.diff-list { font-size: 12px; color: #6b7280; margin-top: 6px; line-height: 1.7; }
|
||||||
.diff-list li { margin-left: 18px; }
|
.diff-list li { margin-left: 18px; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -129,8 +130,9 @@ function setStatus(text, type) {
|
|||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const fileInput = $('imageFile');
|
const fileInput = $('imageFile');
|
||||||
const file = fileInput.files[0];
|
let file = fileInput.files[0];
|
||||||
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const _reqStart = performance.now();
|
const _reqStart = performance.now();
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,7 @@
|
|||||||
|
|
||||||
.badge-v2 { background: #7c3aed; color: #fff; font-size: 11px; padding: 2px 8px; border-radius: 10px; margin-left: 6px; vertical-align: middle; }
|
.badge-v2 { background: #7c3aed; color: #fff; font-size: 11px; padding: 2px 8px; border-radius: 10px; margin-left: 6px; vertical-align: middle; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -137,9 +138,9 @@ function $(id) { return document.getElementById(id); }
|
|||||||
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
function setStatus(t, type) { const b=$('statusBar'); b.textContent=t; b.className='status '+type; }
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const f = $('imageFile').files[0];
|
let f = $('imageFile').files[0];
|
||||||
if (!f) { setStatus('请选择图片', 'error'); return; }
|
if (!f) { setStatus('请选择图片', 'error'); return; }
|
||||||
|
f = await window.downscaleImageFile(f);
|
||||||
|
|
||||||
_origUrl = URL.createObjectURL(f);
|
_origUrl = URL.createObjectURL(f);
|
||||||
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 请求中...';
|
$('submitBtn').disabled = true; $('submitBtn').textContent = '⏳ 请求中...';
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
||||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||||
</style>
|
</style>
|
||||||
|
<script src="/static/img_downscale.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -194,8 +195,9 @@ function renderMetrics(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function submitTest() {
|
async function submitTest() {
|
||||||
const file = $('imageFile').files[0];
|
let file = $('imageFile').files[0];
|
||||||
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
if (!file) { setStatus('请先选择一张图片', 'error'); return; }
|
||||||
|
file = await window.downscaleImageFile(file);
|
||||||
|
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const btn = $('submitBtn');
|
const btn = $('submitBtn');
|
||||||
|
|||||||
Reference in New Issue
Block a user