[Image] 上傳之前HTML5預先調整圖像大小


Answers

幾年前我解決了這個問題,並通過https://github.com/rossturner/HTML5-ImageUploader將我的解決方案上傳到github

robertc的答案使用了Mozilla Hacks博客文章中提出的解決方案,但是當調整到不是2:1(或其倍數)的縮放比例時,我發現這給了非常差的圖像質量。 我開始嘗試使用不同的圖像大小調整算法,雖然大多數結果都很慢,或者質量也不好。

最後,我想出了一個我認為可以快速執行的解決方案,並且性能也非常出色 - 因為從1個畫布複製到另一個畫布的Mozilla解決方案能夠在2:1的比例下快速且不丟失圖像質量,因為x像素寬,像素高,我使用這種畫布調整大小的方法,直到圖像在x和2 xy和2 y之間 。 在這一點上,我接著轉向算法圖像大小調整,以調整最終“尺寸”的大小。 在嘗試了幾種不同的算法之後,我決定採用從不在線的博客取得的雙線性插值,但可以通過Internet Archive進行訪問 ,這會給出好的結果,下面是適用的代碼:

ImageUploader.prototype.scaleImage = function(img, completionCallback) {
    var canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;
    canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);

    while (canvas.width >= (2 * this.config.maxWidth)) {
        canvas = this.getHalfScaleCanvas(canvas);
    }

    if (canvas.width > this.config.maxWidth) {
        canvas = this.scaleCanvasWithAlgorithm(canvas);
    }

    var imageData = canvas.toDataURL('image/jpeg', this.config.quality);
    this.performUpload(imageData, completionCallback);
};

ImageUploader.prototype.scaleCanvasWithAlgorithm = function(canvas) {
    var scaledCanvas = document.createElement('canvas');

    var scale = this.config.maxWidth / canvas.width;

    scaledCanvas.width = canvas.width * scale;
    scaledCanvas.height = canvas.height * scale;

    var srcImgData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
    var destImgData = scaledCanvas.getContext('2d').createImageData(scaledCanvas.width, scaledCanvas.height);

    this.applyBilinearInterpolation(srcImgData, destImgData, scale);

    scaledCanvas.getContext('2d').putImageData(destImgData, 0, 0);

    return scaledCanvas;
};

ImageUploader.prototype.getHalfScaleCanvas = function(canvas) {
    var halfCanvas = document.createElement('canvas');
    halfCanvas.width = canvas.width / 2;
    halfCanvas.height = canvas.height / 2;

    halfCanvas.getContext('2d').drawImage(canvas, 0, 0, halfCanvas.width, halfCanvas.height);

    return halfCanvas;
};

ImageUploader.prototype.applyBilinearInterpolation = function(srcCanvasData, destCanvasData, scale) {
    function inner(f00, f10, f01, f11, x, y) {
        var un_x = 1.0 - x;
        var un_y = 1.0 - y;
        return (f00 * un_x * un_y + f10 * x * un_y + f01 * un_x * y + f11 * x * y);
    }
    var i, j;
    var iyv, iy0, iy1, ixv, ix0, ix1;
    var idxD, idxS00, idxS10, idxS01, idxS11;
    var dx, dy;
    var r, g, b, a;
    for (i = 0; i < destCanvasData.height; ++i) {
        iyv = i / scale;
        iy0 = Math.floor(iyv);
        // Math.ceil can go over bounds
        iy1 = (Math.ceil(iyv) > (srcCanvasData.height - 1) ? (srcCanvasData.height - 1) : Math.ceil(iyv));
        for (j = 0; j < destCanvasData.width; ++j) {
            ixv = j / scale;
            ix0 = Math.floor(ixv);
            // Math.ceil can go over bounds
            ix1 = (Math.ceil(ixv) > (srcCanvasData.width - 1) ? (srcCanvasData.width - 1) : Math.ceil(ixv));
            idxD = (j + destCanvasData.width * i) * 4;
            // matrix to vector indices
            idxS00 = (ix0 + srcCanvasData.width * iy0) * 4;
            idxS10 = (ix1 + srcCanvasData.width * iy0) * 4;
            idxS01 = (ix0 + srcCanvasData.width * iy1) * 4;
            idxS11 = (ix1 + srcCanvasData.width * iy1) * 4;
            // overall coordinates to unit square
            dx = ixv - ix0;
            dy = iyv - iy0;
            // I let the r, g, b, a on purpose for debugging
            r = inner(srcCanvasData.data[idxS00], srcCanvasData.data[idxS10], srcCanvasData.data[idxS01], srcCanvasData.data[idxS11], dx, dy);
            destCanvasData.data[idxD] = r;

            g = inner(srcCanvasData.data[idxS00 + 1], srcCanvasData.data[idxS10 + 1], srcCanvasData.data[idxS01 + 1], srcCanvasData.data[idxS11 + 1], dx, dy);
            destCanvasData.data[idxD + 1] = g;

            b = inner(srcCanvasData.data[idxS00 + 2], srcCanvasData.data[idxS10 + 2], srcCanvasData.data[idxS01 + 2], srcCanvasData.data[idxS11 + 2], dx, dy);
            destCanvasData.data[idxD + 2] = b;

            a = inner(srcCanvasData.data[idxS00 + 3], srcCanvasData.data[idxS10 + 3], srcCanvasData.data[idxS01 + 3], srcCanvasData.data[idxS11 + 3], dx, dy);
            destCanvasData.data[idxD + 3] = a;
        }
    }
};

這將圖像縮小到config.maxWidth的寬度, config.maxWidth保持原始高寬比。 在開發時,除了主要的桌面瀏覽器(IE9 +,Firefox,Chrome)之外,這款產品還適用於iPad / iPhone Safari,所以我期望它能夠在今天更廣泛地吸收HTML5的情況下仍然兼容。 請注意,canvas.toDataURL()調用採用MIME類型和圖像質量,這將允許您控制質量和輸出文件格式(如果您願意,可能會與輸入不同)。

這裡沒有涉及的唯一一點就是維護方向信息,而不知道這個元數據圖像的大小和原樣保存,在圖像中丟失了任何元數據,這就意味著在平板設備上“上下顛倒”拍攝的圖像是儘管它們會在設備的相機取景器中翻轉。 如果這是一個問題, 這個博客文章有一個很好的指導和代碼示例如何實現這一點,我敢肯定可以集成到上面的代碼。

Question

這是一個麵條刮刀。

請記住,我們有HTML5本地存儲和xhr v2,而不是。 我想知道是否有人可以找到一個有效的例子,甚至只是給我一個是或否的問題:

是否有可能使用新的本地存儲(或其他)預先設置圖像大小,以便不知道如何調整圖像大小的用戶可以將其10mb圖像拖入我的網站,使用新的本地存儲調整大小,那麼以較小的尺寸上傳它。

我完全知道你可以用Flash,Java applets,active X來做...問題是如果你可以用Javascript + Html5做。

期待這一次的回應。

Ta現在。




如果你不想重新發明輪子,你可以嘗試plupload.com




fd.append("image", dataurl);

這不起作用。 在PHP方面,你不能用這個保存文件。

改用此代碼:

var blobBin = atob(dataurl.split(',')[1]);
var array = [];
for(var i = 0; i < blobBin.length; i++) {
  array.push(blobBin.charCodeAt(i));
}
var file = new Blob([new Uint8Array(array)], {type: 'image/png', name: "avatar.png"});

fd.append("image", file); // blob file



在canvas元素中調整圖像的大小通常是個壞主意,因為它使用了最便宜的方框插值。 由此產生的圖像顯著降低質量。 我建議使用可以執行Lanczos轉換的http://nodeca.github.io/pica/demo/ 。 上面的演示頁面顯示了畫布和Lanczos方法之間的區別。

它還使用網絡工作人員並行調整圖像大小。 還有WEBGL實現。

有一些在線圖像調整器使用pica來完成這項工作,例如https://myimageresizer.com