una tamaño reducir pixelada perder minimizar mejorar imagenes imagen hacer grande escalar como capa calidad javascript html5 canvas scaling interpolation

javascript - tamaño - mejorar imagen pixelada gimp



¿Cómo escalar imágenes en un lienzo html5 con una mejor interpolación? (1)

Necesita "bajar" varias veces. En lugar de escalar de una imagen muy grande a una muy pequeña, debe volver a escalarla a tamaños intermedios.

Considera una imagen que quieras dibujar a escala 1/6. Podrías hacer esto:

var w = 1280; var h = 853; ctx.drawImage(img, 0, 0, w/6, h/6);

O puede dibujarlo en un lienzo en memoria en 1/2 escala, luego 1/2 escala nuevamente, luego 1/2 escala nuevamente. El resultado es una imagen a escala 1/6, pero usamos tres pasos:

var can2 = document.createElement(''canvas''); can2.width = w/2; can2.height = w/2; var ctx2 = can2.getContext(''2d''); ctx2.drawImage(img, 0, 0, w/2, h/2); ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4); ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6);

Luego, puede volver a dibujarlo en su contexto original:

ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6);

Puedes ver la diferencia en vivo, aquí:

var can = document.getElementById(''canvas1''); var ctx = can.getContext(''2d''); var img = new Image(); var w = 1280; var h = 853; img.onload = function() { // step it down only once to 1/6 size: ctx.drawImage(img, 0, 0, w/6, h/6); // Step it down several times var can2 = document.createElement(''canvas''); can2.width = w/2; can2.height = w/2; var ctx2 = can2.getContext(''2d''); // Draw it at 1/2 size 3 times (step down three times) ctx2.drawImage(img, 0, 0, w/2, h/2); ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4); ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6); ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6); } img.src = ''http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Equus_quagga_%28Namutoni%2C_2012%29.jpg/1280px-Equus_quagga_%28Namutoni%2C_2012%29.jpg''

canvas { border: 1px solid gray; }

<canvas id="canvas1" width="400" height="400"></canvas>

Ver el mismo fragmento en jsfiddle.

En primer lugar, ¿qué estoy tratando de hacer?

Tengo una aplicación para ver imágenes. Utiliza el elemento canvas para representar la imagen. Puede acercar, alejar y puede arrastrarlo. Esta parte funciona perfectamente en este momento.

Pero digamos que tengo una imagen con mucho texto. Tiene una resolución de 1200x1700, y mi lienzo tiene 1200x900. Inicialmente, cuando se aleja, esto lleva a una resolución renderizada de ~ 560x800.

Mi dibujo real se ve así:

drawImage(src, srcOffsetX, srcOffsetY, sourceViewWidth, sourceViewHeight, destOffsetX, destOffsetY, destWidth, destHeight);

El texto pequeño en esta imagen se ve muy, muy mal, especialmente cuando se compara con otros visores de imágenes (por ejemplo, IrfanView), o incluso el elemento html <img>.

Descubrí que el algoritmo de interpolación de los navegadores es la causa de este problema. La comparación de diferentes navegadores mostró que Chrome hace que las imágenes escaladas sean las mejores, pero aún no lo suficientemente buenas.

Bueno, busqué en cada esquina de Interwebs durante 4-5 horas seguidas y no encontré lo que necesitaba. Encontré la opción "imageSmoothingEnabled", los estilos CSS de "renderización de imágenes" que no se pueden usar en el lienzo, la representación en posiciones flotantes y muchas implementaciones de JavaScript de algoritmos de interpolación (los cuales son lentos para mi propósito).

Puede preguntar por qué le digo todo esto: para ahorrarle tiempo para darme respuestas, ya lo sé :))

Entonces, ¿hay alguna manera buena y rápida de tener una mejor interpolación? Mi idea actual es crear un objeto de imagen, cambiar el tamaño de esto (¡porque img tiene una buena interpolación cuando se escala!) Y renderizarlo en ese momento. Desafortunadamente, la aplicación de img.width solo parece afectar el ancho mostrado ...

Muchas gracias de antemano por sus respuestas !! :)

Actualización : Gracias a Simon, pude resolver mi problema. Aquí está el algoritmo de escalamiento dinámico que utilicé. Tenga en cuenta que mantiene la relación de aspecto, el parámetro de altura es solo para evitar más computación flotante. Solo se reduce en este momento.

scale(destWidth, destHeight){ var start = new Date().getTime(); var scalingSteps = 0; var ctx = this._sourceImageCanvasContext; var curWidth = this._sourceImageWidth; var curHeight = this._sourceImageHeight; var lastWidth = this._sourceImageWidth; var lastHeight = this._sourceImageHeight; var end = false; var scale=0.75; while(end==false){ scalingSteps +=1; curWidth *= scale; curHeight *= scale; if(curWidth < destWidth){ curWidth = destWidth; curHeight = destHeight; end=true; } ctx.drawImage(this._sourceImageCanvas, 0, 0, Math.round(lastWidth), Math.round(lastHeight), 0, 0, Math.round(curWidth), Math.round(curHeight)); lastWidth = curWidth; lastHeight = curHeight; } var endTime =new Date().getTime(); console.log("execution time: "+ ( endTime - start) + "ms. scale per frame: "+scale+ " scaling step count: "+scalingSteps); }