Dimensionar a imagem com a área de desenho javascript (sem problemas)

Estou a tentar redimensionar algumas imagens com tela, mas não sei como suavizá-las. On photoshop, browsers etc.. existem alguns algoritmos que eles usam (por exemplo, bicúbico, bilinear), mas eu não sei se estes são construídos em tela ou não.

Aqui está o meu violino. http://jsfiddle.net/EWupT/

  var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    canvas.width=300
    canvas.height=234
    ctx.drawImage(img, 0, 0, 300, 234);
    document.body.appendChild(canvas);

o primeiro é uma marca de imagem redimensionada normal, e o segundo é tela. Repare como a tela não é tão suave. Como posso alcançar a "suavidade"?

Author: steve, 2013-10-09

6 answers

Podes usar descer para obter melhores resultados. A maioria dos navegadores parece usar interpolação linear em vez de bi-cúbico ao dimensionar imagens.

(Update foi adicionada uma propriedade de qualidade às especificações, imageSmoothingQuality que está disponível apenas no Chrome.)

A menos que se opte por não suavizar ou pelo vizinho mais próximo, o navegador irá sempre interpolar a imagem depois de a reduzir como esta função como um filtro de baixa passagem para evitar suavizacao.

O Bi-linear usa 2x2 pixels para fazer a interpolação, enquanto o bi-cúbico usa 4x4 de modo a fazê-lo em etapas, poderá aproximar-se do resultado bi-cúbico ao usar a interpolação bi-linear, como é visto nas imagens resultantes.

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();

img.onload = function () {

    // set size proportional to image
    canvas.height = canvas.width * (img.height / img.width);

    // step 1 - resize to 50%
    var oc = document.createElement('canvas'),
        octx = oc.getContext('2d');

    oc.width = img.width * 0.5;
    oc.height = img.height * 0.5;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

    // step 2
    octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);

    // step 3, resize to final size
    ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
    0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>

Dependendo de quão drástico é o seu redimensionamento, pode saltar o PASSO 2 se a diferença for menor.

Na demonstração, você pode ver que o novo resultado é agora muito semelhante ao elemento imagem.

 101
Author: epistemex, 2017-11-03 03:51:24
Criei um serviço Angular reutilizável para lidar com o redimensionamento de imagens / telas de alta qualidade para quem estiver interessado. https://gist.github.com/transitive-bullshit/37bac5e741eaec60e983 O serviço inclui duas soluções porque ambas têm os seus prós e contras. A abordagem de convolução de lanczos é de maior qualidade ao custo de ser mais lento, enquanto que a abordagem de redução gradual produz resultados razoavelmente anti-aleatórios e é significativamente rapidamente.

Uso de exemplo:

angular.module('demo').controller('ExampleCtrl', function (imageService) {
  // EXAMPLE USAGE
  // NOTE: it's bad practice to access the DOM inside a controller, 
  // but this is just to show the example usage.

  // resize by lanczos-sinc filter
  imageService.resize($('#myimg')[0], 256, 256)
    .then(function (resizedImage) {
      // do something with resized image
    })

  // resize by stepping down image size in increments of 2x
  imageService.resizeStep($('#myimg')[0], 256, 256)
    .then(function (resizedImage) {
      // do something with resized image
    })
})
 16
Author: fisch2, 2018-01-24 07:19:48

Uma Vez Que Trung Le Nguyen o violino de Nhat não está correcto de todo (ele apenas usa a imagem original no último passo)
Eu escrevi meu próprio violino geral com comparação de desempenho:

Violino

Basicamente é:
img.onload = function() {
   var canvas = document.createElement('canvas'),
       ctx = canvas.getContext("2d"),
       oc = document.createElement('canvas'),
       octx = oc.getContext('2d');

   canvas.width = width; // destination canvas size
   canvas.height = canvas.width * img.height / img.width;

   var cur = {
     width: Math.floor(img.width * 0.5),
     height: Math.floor(img.height * 0.5)
   }

   oc.width = cur.width;
   oc.height = cur.height;

   octx.drawImage(img, 0, 0, cur.width, cur.height);

   while (cur.width * 0.5 > width) {
     cur = {
       width: Math.floor(cur.width * 0.5),
       height: Math.floor(cur.height * 0.5)
     };
     octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
   }

   ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
}
 8
Author: Sebastian Ott, 2017-05-23 11:55:05

Criei uma biblioteca que lhe permite descer qualquer percentagem mantendo todos os dados de cores.

Https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

O ficheiro que pode incluir no navegador. Os resultados serão parecidos com photoshop ou image magick, preservando todos os dados de cor, média de pixels, em vez de tomar próximo uns e deixar cair outros. Ele não usa uma fórmula para adivinhar as médias, ele leva a média exata.

 4
Author: Funkodebat, 2014-07-30 20:00:18

Baseado na resposta do K3N, eu reescrevo o código geralmente para quem quiser

var oc = document.createElement('canvas'), octx = oc.getContext('2d');
    oc.width = img.width;
    oc.height = img.height;
    octx.drawImage(img, 0, 0);
    while (oc.width * 0.5 > width) {
       oc.width *= 0.5;
       oc.height *= 0.5;
       octx.drawImage(oc, 0, 0, oc.width, oc.height);
    }
    oc.width = width;
    oc.height = oc.width * img.height / img.width;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

ACTUALIZAR A DEMONSTRAÇÃO DO JSFIDDLE

Aqui está o meu demonstração 'ONLINE'
 1
Author: Trung Le Nguyen Nhat, 2016-06-08 03:08:09

Escrevi uma pequena js-utility para recortar e redimensionar a imagem na frente. Aqui está link no projecto GitHub. Também você pode obter blob da imagem final para enviá-lo.

import imageSqResizer from './image-square-resizer.js'

let resizer = new imageSqResizer(
    'image-input',
    300,
    (dataUrl) => 
        document.getElementById('image-output').src = dataUrl;
);
//Get blob
let formData = new FormData();
formData.append('files[0]', resizer.blob);

//get dataUrl
document.getElementById('image-output').src = resizer.dataUrl;
 1
Author: Diyaz Yakubov, 2017-11-14 13:42:01