자바 스크립트와 캔버스 요소를 사용하여 클라이언트 측에서 축소판 이미지를 만들려고하는데 이미지를 축소하면 끔찍한 것처럼 보입니다. Bicubic 대신 ‘Nearest Neighbor’로 리샘플링을 설정 한 상태에서 포토샵에서 축소 된 것처럼 보입니다. 이 사이트 가 캔버스를 사용하여 잘 수행 할 수 있기 때문에 이것이 올바르게 보이도록하는 것이 가능하다는 것을 알고 있습니다. “[Source]”링크에 표시된 것과 동일한 코드를 사용해 보았지만 여전히 끔찍합니다. 내가 놓친 것이 있습니까, 설정해야 할 설정이 있습니까?
편집하다:
jpg의 크기를 조정하려고합니다. 링크 된 사이트와 포토샵에서 동일한 jpg 크기를 조정하려고 시도했으며 크기가 작을 때 잘 보입니다.
관련 코드는 다음과 같습니다.
reader.onloadend = function(e)
{
    var img = new Image();
    var ctx = canvas.getContext("2d");
    var canvasCopy = document.createElement("canvas");
    var copyContext = canvasCopy.getContext("2d");
    img.onload = function()
    {
        var ratio = 1;
        if(img.width > maxWidth)
            ratio = maxWidth / img.width;
        else if(img.height > maxHeight)
            ratio = maxHeight / img.height;
        canvasCopy.width = img.width;
        canvasCopy.height = img.height;
        copyContext.drawImage(img, 0, 0);
        canvas.width = img.width * ratio;
        canvas.height = img.height * ratio;
        ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
    };
    img.src = reader.result;
}
EDIT2 :
내가 잘못 생각한 것 같습니다. 링크 된 웹 사이트가 이미지 크기를 줄이는 작업을 더 잘 수행하지 못했습니다. 나는 제안 된 다른 방법을 시도했지만 그중 어느 것도 더 좋아 보이지 않습니다. 이것은 다른 방법으로 얻은 것입니다.
포토샵 :

캔버스:

이미지 렌더링이 포함 된 이미지 : optimizeQuality가 너비 / 높이로 설정 및 조정됩니다.

이미지 렌더링이 포함 된 이미지 : -moz-transform을 사용하여 품질 설정 및 스케일 조정 :

pixastic에서 캔버스 크기 조정 :

나는 이것이 파이어 폭스가 예상대로 바이 큐빅 샘플링을 사용하지 않는다는 것을 의미한다고 생각합니다. 실제로 추가 할 때까지 기다려야합니다.
EDIT3 :
답변
모든 브라우저 (실제로 Chrome 5에서 나에게 아주 좋은 것을 주 었음)가 충분한 리샘플링 품질을 제공하지 못하면 어떻게해야합니까? 그런 다음 직접 구현하십시오! 오, 우리는 웹 3.0, HTML5 호환 브라우저, 슈퍼 최적화 된 JIT 자바 스크립트 컴파일러, 멀티 코어 (†) 머신, 수많은 메모리를 가진 새로운 시대에 접어 들고 있습니다. 이봐, 자바 스크립트에 java라는 단어가 있으므로 성능을 보장해야합니다. 썸네일 생성 코드 :
// returns a function that calculates lanczos weight
function lanczosCreate(lobes) {
    return function(x) {
        if (x > lobes)
            return 0;
        x *= Math.PI;
        if (Math.abs(x) < 1e-16)
            return 1;
        var xx = x / lobes;
        return Math.sin(x) * Math.sin(xx) / x / xx;
    };
}
// elem: canvas element, img: image element, sx: scaled width, lobes: kernel radius
function thumbnailer(elem, img, sx, lobes) {
    this.canvas = elem;
    elem.width = img.width;
    elem.height = img.height;
    elem.style.display = "none";
    this.ctx = elem.getContext("2d");
    this.ctx.drawImage(img, 0, 0);
    this.img = img;
    this.src = this.ctx.getImageData(0, 0, img.width, img.height);
    this.dest = {
        width : sx,
        height : Math.round(img.height * sx / img.width),
    };
    this.dest.data = new Array(this.dest.width * this.dest.height * 3);
    this.lanczos = lanczosCreate(lobes);
    this.ratio = img.width / sx;
    this.rcp_ratio = 2 / this.ratio;
    this.range2 = Math.ceil(this.ratio * lobes / 2);
    this.cacheLanc = {};
    this.center = {};
    this.icenter = {};
    setTimeout(this.process1, 0, this, 0);
}
thumbnailer.prototype.process1 = function(self, u) {
    self.center.x = (u + 0.5) * self.ratio;
    self.icenter.x = Math.floor(self.center.x);
    for (var v = 0; v < self.dest.height; v++) {
        self.center.y = (v + 0.5) * self.ratio;
        self.icenter.y = Math.floor(self.center.y);
        var a, r, g, b;
        a = r = g = b = 0;
        for (var i = self.icenter.x - self.range2; i <= self.icenter.x + self.range2; i++) {
            if (i < 0 || i >= self.src.width)
                continue;
            var f_x = Math.floor(1000 * Math.abs(i - self.center.x));
            if (!self.cacheLanc[f_x])
                self.cacheLanc[f_x] = {};
            for (var j = self.icenter.y - self.range2; j <= self.icenter.y + self.range2; j++) {
                if (j < 0 || j >= self.src.height)
                    continue;
                var f_y = Math.floor(1000 * Math.abs(j - self.center.y));
                if (self.cacheLanc[f_x][f_y] == undefined)
                    self.cacheLanc[f_x][f_y] = self.lanczos(Math.sqrt(Math.pow(f_x * self.rcp_ratio, 2)
                            + Math.pow(f_y * self.rcp_ratio, 2)) / 1000);
                weight = self.cacheLanc[f_x][f_y];
                if (weight > 0) {
                    var idx = (j * self.src.width + i) * 4;
                    a += weight;
                    r += weight * self.src.data[idx];
                    g += weight * self.src.data[idx + 1];
                    b += weight * self.src.data[idx + 2];
                }
            }
        }
        var idx = (v * self.dest.width + u) * 3;
        self.dest.data[idx] = r / a;
        self.dest.data[idx + 1] = g / a;
        self.dest.data[idx + 2] = b / a;
    }
    if (++u < self.dest.width)
        setTimeout(self.process1, 0, self, u);
    else
        setTimeout(self.process2, 0, self);
};
thumbnailer.prototype.process2 = function(self) {
    self.canvas.width = self.dest.width;
    self.canvas.height = self.dest.height;
    self.ctx.drawImage(self.img, 0, 0, self.dest.width, self.dest.height);
    self.src = self.ctx.getImageData(0, 0, self.dest.width, self.dest.height);
    var idx, idx2;
    for (var i = 0; i < self.dest.width; i++) {
        for (var j = 0; j < self.dest.height; j++) {
            idx = (j * self.dest.width + i) * 3;
            idx2 = (j * self.dest.width + i) * 4;
            self.src.data[idx2] = self.dest.data[idx];
            self.src.data[idx2 + 1] = self.dest.data[idx + 1];
            self.src.data[idx2 + 2] = self.dest.data[idx + 2];
        }
    }
    self.ctx.putImageData(self.src, 0, 0);
    self.canvas.style.display = "block";
};
… 이러한 결과를 얻을 수 있습니다!

어쨌든 다음은 예제의 ‘고정’버전입니다.
img.onload = function() {
    var canvas = document.createElement("canvas");
    new thumbnailer(canvas, img, 188, 3); //this produces lanczos3
    // but feel free to raise it up to 8. Your client will appreciate
    // that the program makes full use of his machine.
    document.body.appendChild(canvas);
};
이제 최고의 브라우저를 사용하여 고객의 혈압을 높일 가능성이 가장 높은 브라우저를 확인하십시오.
음, 풍자 태그는 어디에 있습니까?
(코드의 많은 부분이 Anrieff Gallery Generator를 기반으로 하기 때문에 GPL2에도 적용됩니까?
† 실제로 자바 스크립트 제한으로 인해 멀티 코어는 지원되지 않습니다.
답변
JavaScript로 Hermite 필터를 사용하여 빠른 이미지 크기 조정 / 재 샘플링 알고리즘 . 투명성을 지원하고 좋은 품질을 제공합니다. 시사:

업데이트 : GitHub에 버전 2.0이 추가되었습니다 (빠른 웹 워커 + 전송 가능한 개체). 마침내 나는 그것을 작동시켰다!
힘내 : https://github.com/viliusle/Hermite-resize
데모 : http://viliusle.github.io/miniPaint/
/**
 * Hermite resize - fast image resize/resample using Hermite filter. 1 cpu version!
 * 
 * @param {HtmlElement} canvas
 * @param {int} width
 * @param {int} height
 * @param {boolean} resize_canvas if true, canvas will be resized. Optional.
 */
function resample_single(canvas, width, height, resize_canvas) {
    var width_source = canvas.width;
    var height_source = canvas.height;
    width = Math.round(width);
    height = Math.round(height);
    var ratio_w = width_source / width;
    var ratio_h = height_source / height;
    var ratio_w_half = Math.ceil(ratio_w / 2);
    var ratio_h_half = Math.ceil(ratio_h / 2);
    var ctx = canvas.getContext("2d");
    var img = ctx.getImageData(0, 0, width_source, height_source);
    var img2 = ctx.createImageData(width, height);
    var data = img.data;
    var data2 = img2.data;
    for (var j = 0; j < height; j++) {
        for (var i = 0; i < width; i++) {
            var x2 = (i + j * width) * 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;
            var yy_start = Math.floor(j * ratio_h);
            var yy_stop = Math.ceil((j + 1) * ratio_h);
            for (var yy = yy_start; yy < yy_stop; 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
                var xx_start = Math.floor(i * ratio_w);
                var xx_stop = Math.ceil((i + 1) * ratio_w);
                for (var xx = xx_start; xx < xx_stop; xx++) {
                    var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
                    var w = Math.sqrt(w0 + dx * dx);
                    if (w >= 1) {
                        //pixel too far
                        continue;
                    }
                    //hermite filter
                    weight = 2 * w * w * w - 3 * w * w + 1;
                    var pos_x = 4 * (xx + yy * width_source);
                    //alpha
                    gx_a += weight * data[pos_x + 3];
                    weights_alpha += weight;
                    //colors
                    if (data[pos_x + 3] < 255)
                        weight = weight * data[pos_x + 3] / 250;
                    gx_r += weight * data[pos_x];
                    gx_g += weight * data[pos_x + 1];
                    gx_b += weight * data[pos_x + 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;
        }
    }
    //clear and resize canvas
    if (resize_canvas === true) {
        canvas.width = width;
        canvas.height = height;
    } else {
        ctx.clearRect(0, 0, width_source, height_source);
    }
    //draw
    ctx.putImageData(img2, 0, 0);
}
답변
선택 가능한 알고리즘을 가진 고도로 최적화 된 크기 조정기 인 pica를 사용해보십시오 . 데모를 참조하십시오 .
예를 들어, 첫 번째 게시물의 원본 이미지는 Lanczos 필터 및 3px 창에서 120ms 또는 상자 필터 및 0.5px 창에서 60ms로 크기가 조정됩니다. 대형 17MB 이미지의 경우 5000x3000px 크기 조정은 데스크톱에서 1 초, 모바일에서 3 초가 걸립니다.
이 스레드에서는 모든 크기 조정 원칙을 잘 설명했으며 pica는 로켓 과학을 추가하지 않습니다. 그러나 최신 JIT에 최적화되어 있으며 npm 또는 bower를 통해 즉시 사용할 수 있습니다. 또한 인터페이스 정지를 피하기 위해 웹 워커를 사용합니다.
언 스케일 마스크 지원도 곧 추가 할 계획입니다. 축소 후 매우 유용하기 때문입니다.
답변
나는 이것이 오래된 스레드라는 것을 알고 있지만 몇 달 후 처음 으로이 문제를 겪은 나 자신과 같은 일부 사람들에게는 유용 할 수 있습니다.
다음은 이미지를 다시로드 할 때마다 이미지 크기를 조정하는 코드입니다. 나는 이것이 최적이 아니라는 것을 알고 있지만 개념 증명으로 제공합니다.
또한 간단한 선택기에 jQuery를 사용하여 죄송하지만 구문에 너무 익숙합니다.
$(document).on('ready', createImage);
$(window).on('resize', createImage);
var createImage = function(){
  var canvas = document.getElementById('myCanvas');
  canvas.width = window.innerWidth || $(window).width();
  canvas.height = window.innerHeight || $(window).height();
  var ctx = canvas.getContext('2d');
  img = new Image();
  img.addEventListener('load', function () {
    ctx.drawImage(this, 0, 0, w, h);
  });
  img.src = 'http://www.ruinvalor.com/Telanor/images/original.jpg';
};html, body{
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
  background: #000;
}
canvas{
  position: absolute;
  left: 0;
  top: 0;
  z-index: 0;
}<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Canvas Resize</title>
  </head>
  <body>
    <canvas id="myCanvas"></canvas>
  </body>
</html>내 createImage 함수는 문서가로드 될 때 한 번 호출 된 후 창에서 크기 조정 이벤트를받을 때마다 호출됩니다.
Mac에서 Chrome 6 및 Firefox 3.6에서 테스트했습니다. 이 “기술”은 여름에 아이스크림 인 것처럼 프로세서를 먹지만 속임수를 씁니다.
답변
여기에 유용 할 수있는 HTML 캔버스 픽셀 배열에서 이미지 보간을 수행하는 알고리즘을 작성했습니다.
https://web.archive.org/web/20170104190425/http://jsperf.com:80/pixel-interpolation/2
이것들은 복사 / 붙여 넣기를 할 수 있으며 웹 워커 내부에서 이미지의 크기를 조정하는 데 사용할 수 있습니다 (또는 보간이 필요한 다른 작업 – 현재 이미지를 제거하는 데 사용하고 있습니다).
위의 lanczos 항목을 추가하지 않았으므로 원하는 경우 비교로 추가하십시오.
답변
이것은 @Telanor의 코드에서 채택 된 자바 스크립트 함수입니다. 이미지 base64를 함수의 첫 번째 인수로 전달하면 크기가 조정 된 이미지의 base64를 반환합니다. maxWidth 및 maxHeight는 선택 사항입니다.
function thumbnail(base64, maxWidth, maxHeight) {
  // Max size for thumbnail
  if(typeof(maxWidth) === 'undefined') var maxWidth = 500;
  if(typeof(maxHeight) === 'undefined') var maxHeight = 500;
  // Create and initialize two canvas
  var canvas = document.createElement("canvas");
  var ctx = canvas.getContext("2d");
  var canvasCopy = document.createElement("canvas");
  var copyContext = canvasCopy.getContext("2d");
  // Create original image
  var img = new Image();
  img.src = base64;
  // Determine new ratio based on max size
  var ratio = 1;
  if(img.width > maxWidth)
    ratio = maxWidth / img.width;
  else if(img.height > maxHeight)
    ratio = maxHeight / img.height;
  // Draw original image in second canvas
  canvasCopy.width = img.width;
  canvasCopy.height = img.height;
  copyContext.drawImage(img, 0, 0);
  // Copy and resize second canvas to first canvas
  canvas.width = img.width * ratio;
  canvas.height = img.height * ratio;
  ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
  return canvas.toDataURL();
}