兩個框為什麼會在一張圖上互相打架
一張自造的 1237×859 純色圖(非照片)拖進去,鎖著時把寬打 800,高框寫回「556」;再把高框手打成 300,它又變回「556」。滑桿那頭:同一張 PNG 縮到 619×430,品質從 10 拖到 100,四輪結果行都是「619 × 430 | 6.8 KB」。這頁模板 12308 位元組 / 265 行,腳本原樣跑兩路:node:vm 樁與 Chrome 154 真編碼器。
被測的是圖片尺寸調整,全頁本地處理,grep fetch( 命中 0 處。
鎖只讀寬、只寫高
onSizeInput(L188–L192)鎖著時只讀寬框、只算 Math.round(寬 / aspectRatio)、只寫高框。aspectRatio 存的是 1237/859=1.440046565774156 這個浮點商,不是既約比,於是手打的高必被覆蓋:寬 800 + 手打高 300 → 高框留「556」。toggleLock(L181–L185)解鎖後兩框各走各的。
| 鎖著時寬框 | 高框 | 除法原值 |
|---|---|---|
| 859 | 597 | 596.5084882780922 |
這把尺在原圖上共掃 18 檔(1237→「859」、400→「278」),寬打 1 時靠進位保住高 1。
百分比是兩把獨立的尺
onPercentInput(L195–L200)對寬高各跑一次 Math.round,完全不看 aspectLocked。pct=50 → 619×430,理想 618.5 × 429.5,兩框之和 1049 對 1048、差 1。兩軸同時以 .5 結尾的 p 有 10 檔,Math.round 對正 .5 一律進位;pct 從 1 掃到 1000,120 檔兩條路的高不等。
圖 1:pct=1 那檔兩條路給出兩種長寬比。
比例框從不回頭讀寬高框
switchMode(L172–L178)只改 currentMode 與兩個面板的 display,沒有任何一行程式碼回寫 resize-percent。點 150% → 切回 pixel → 把寬手打 400(高被算成 278),比例框全程仍顯示「150」;反推值 100*1856/1237=150.0404% 不等於框裡的 150——框裡存的是「點過的檔」。再點一次 setPercent(150)(L203–L206)就把兩框打回 1856×1289,剛手打的 400 蒸發。
滑桿在 PNG 上為什麼一個位元組都不動
本機 Chrome 154 只有三個真編碼器,1×1 畫布上 png / jpeg / webp 分別回 110 / 762 / 552 B。L229 把滑桿值除 100 交給 toBlob,PNG 編碼器不吃這個參數;BMP 又疊一層——L228 把輸出改寫成 PNG,而 L152 只給 image/jpeg / image/webp 顯示品質行,滑桿本身 display:none。
| 619×430 的 blob | q10 | q50 | q90 | q100 |
|---|---|---|---|---|
| PNG | 6971 | 6971 | 6971 | 6971 |
| JPEG | 2338 | 2340 | 2341 | 3921 |
| WEBP | 1092 | 1102 | 1050 | 4684 |
JPEG 的 10→90 三檔只差 3 B;WEBP 的 q90 比 q10 小(1050<1092),編碼器不保證單調;BMP 源(3188662 B)六檔全 6971 B。同族幾頁共用這一份模板,那幾頁的位元組帳不在本篇。順帶說明:這組數字全部出自同一份 blob 的四次重新編碼,而不是四次重新縮放。
結果行那串字面怎麼拼
L235 是 w + ' × ' + h + ' | ' + formatSize(blob.size),w/h 取 JS 裡的整數而非畫布屬性,「 × 」是 3 碼元/4 位元組。formatSize(L165–L169)分三檔:B 檔原樣整數、KB 檔 toFixed(1)、MB 檔 toFixed(2),閾值 1024 與 1048576,實測 1024→「1.0 KB」、1075→「1.0 KB」而 1076→「1.1 KB」、1048576→「1.00 MB」。壓位元組走另一條通道,見圖片壓縮;那篇透傳的實測量的是別一頁。
三閘與它攔不住的那些
doResize(L209–L237)只三道閘:無圖、parseInt 出 NaN 或 ≤0、w>10000 || h>10000;JS 不設下限校驗,min="1" / max="10000" 只是控件屬性:「10001」瀏覽器不攔,走到 L216 才彈「尺寸不能超過 10000px」。最安靜的是「1e5」:parseInt 遇 e 停讀成 1,無 toast 真出圖,結果行「1 × 1 | 762 B」,輸入與產出差 5 個數量級。只有滑桿被瀏覽器硬夾(打 9 →「10」),L229 因此落在 10..100。
失敗之後屏上留著的是上一張
出過「1 × 1 | 762 B」之後再打 w=619 / h=0,彈「請輸入有效的寬高尺寸」,結果行仍讀上一句。更實在的是不落地那格:先出 619×430 的 webp(「619 × 430 | 1.0 KB」、1050 B),再打 10000×10000 的 webp:回調不來,畫布屬性卻已被 L221–L222 同步改成 10000x10000,結果行仍是上一句、下載仍是上一檔那 1050 B。resetAll(L253–L263)之後七個狀態量逐字不變。
批量是實測出來的「沒有」:files.length 0 處、for( 0 處、progress 0 處,兩處 files[ 只取 [0];一次拖入 2 個檔案只有第 1 張進 handleFile。重採樣演算法與 imageSmoothingQuality(頁面從不讀它,無像素級判據可反推核函數)、佇列與耗時(無佇列程式碼即無物件可測)、介面渲染像素(無渲染器判據),一律標未實測。
順帶對一眼文案
config/tools.php 的 image-resize 條目 16 條主張逐條判:[一致] 6、[部分一致] 7、[衝突] 3。衝突三條:「另一邊」只對一半、「證件照」檔鎖著時輸入 295 得 205 而不是 413(差 -208,要先解鎖而文案未提)、「縮圖批量」零通道。
常見問題
Q:鎖著時手打高度為什麼被打回?
鎖只在寬→高一個方向寫,手打值在回寫那一步被覆蓋。
Q:pct 50 得 619×430,是等比嗎?
它是寬高各過一次 Math.round:619/430=1.4395348837209303 對源比差 -0.0355%,1..1000 裡 120 檔與鎖尺不等。
Q:滑桿拉滿為什麼位元組沒變?
PNG 與被 L228 改寫成 PNG 的 BMP 不吃 quality,四輪同字面;只有 JPEG / WEBP 變位元組。