From a1c419dc71b51457a384a496079b15fec1985078 Mon Sep 17 00:00:00 2001 From: Olivier Paroz Date: Tue, 29 Sep 2015 16:32:43 +0200 Subject: [PATCH] Use Hermite resampling for comparator canvas previews --- core/js/oc-dialogs.js | 93 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 8 deletions(-) diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js index 38b91be9d2..c38250c79c 100644 --- a/core/js/oc-dialogs.js +++ b/core/js/oc-dialogs.js @@ -342,11 +342,12 @@ var OCdialogs = { var crop = function(img) { var canvas = document.createElement('canvas'), - width = img.width, - height = img.height, - x, y, size; + targetSize = 96, + width = img.width, + height = img.height, + x, y, size; - // calculate the width and height, constraining the proportions + // Calculate the width and height, constraining the proportions if (width > height) { y = 0; x = (width - height) / 2; @@ -356,14 +357,90 @@ var OCdialogs = { } size = Math.min(width, height); - // resize the canvas and draw the image data into it - canvas.width = 64; - canvas.height = 64; + // Set canvas size to the cropped area + canvas.width = size; + canvas.height = size; var ctx = canvas.getContext("2d"); - ctx.drawImage(img, x, y, size, size, 0, 0, 64, 64); + ctx.drawImage(img, x, y, size, size, 0, 0, size, size); + + // Resize the canvas to match the destination (right size uses 96px) + resampleHermite(canvas, size, size, targetSize, targetSize); + return canvas.toDataURL("image/png", 0.7); }; + /** + * Fast image resize/resample using Hermite filter with JavaScript. + * + * @author: ViliusL + * + * @param {*} canvas + * @param {number} W + * @param {number} H + * @param {number} W2 + * @param {number} H2 + */ + var resampleHermite = function (canvas, W, H, W2, H2) { + W2 = Math.round(W2); + H2 = Math.round(H2); + var img = canvas.getContext("2d").getImageData(0, 0, W, H); + var img2 = canvas.getContext("2d").getImageData(0, 0, W2, H2); + var data = img.data; + var data2 = img2.data; + var ratio_w = W / W2; + var ratio_h = H / H2; + var ratio_w_half = Math.ceil(ratio_w / 2); + var ratio_h_half = Math.ceil(ratio_h / 2); + + for (var j = 0; j < H2; j++) { + for (var i = 0; i < W2; i++) { + var x2 = (i + j * W2) * 4; + var weight = 0; + var weights = 0; + var weights_alpha = 0; + var gx_r = 0; + var gx_g = 0; + var gx_b = 0; + var gx_a = 0; + var center_y = (j + 0.5) * ratio_h; + for (var yy = Math.floor(j * ratio_h); yy < (j + 1) * ratio_h; yy++) { + var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half; + var center_x = (i + 0.5) * ratio_w; + var w0 = dy * dy; //pre-calc part of w + for (var xx = Math.floor(i * ratio_w); xx < (i + 1) * ratio_w; xx++) { + var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half; + var w = Math.sqrt(w0 + dx * dx); + if (w >= -1 && w <= 1) { + //hermite filter + weight = 2 * w * w * w - 3 * w * w + 1; + if (weight > 0) { + dx = 4 * (xx + yy * W); + //alpha + gx_a += weight * data[dx + 3]; + weights_alpha += weight; + //colors + if (data[dx + 3] < 255) + weight = weight * data[dx + 3] / 250; + gx_r += weight * data[dx]; + gx_g += weight * data[dx + 1]; + gx_b += weight * data[dx + 2]; + weights += weight; + } + } + } + } + data2[x2] = gx_r / weights; + data2[x2 + 1] = gx_g / weights; + data2[x2 + 2] = gx_b / weights; + data2[x2 + 3] = gx_a / weights_alpha; + } + } + canvas.getContext("2d").clearRect(0, 0, Math.max(W, W2), Math.max(H, H2)); + canvas.width = W2; + canvas.height = H2; + canvas.getContext("2d").putImageData(img2, 0, 0); + }; + var addConflict = function($conflicts, original, replacement) { var $conflict = $conflicts.find('.template').clone().removeClass('template').addClass('conflict');