images - resize image javascript before upload
Cambiar el tamaƱo de una imagen en un lienzo HTML5 (18)
Estoy tratando de crear una imagen en miniatura en el lado del cliente usando javascript y un elemento de lienzo, pero cuando encoge la imagen, se ve terrible. Parece como si se redujera en photoshop con el remuestreo configurado en ''Vecino más cercano'' en lugar de Bicubic. Sé que es posible hacer que esto se vea bien, porque este sitio puede hacerlo bien usando un lienzo también. He intentado usar el mismo código que hacen como se muestra en el enlace "[Fuente]", pero aún se ve terrible. ¿Hay algo que me esté perdiendo, alguna configuración que deba establecerse o algo?
EDITAR:
Estoy tratando de cambiar el tamaño de un jpg. He intentado cambiar el tamaño del mismo jpg en el sitio vinculado y en photoshop, y se ve bien cuando se reduce el tamaño.
Aquí está el código relevante:
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:
Parece que me equivoqué, el sitio web vinculado no estaba haciendo mejor trabajo de reducción de la imagen. Probé los otros métodos sugeridos y ninguno de ellos se ve mejor. Esto es lo que los diferentes métodos dieron como resultado:
Photoshop:
Lona:
Imagen con representación de imagen: conjunto de calidad optimizada y escalado con ancho / alto:
Imagen con representación de imagen: conjunto de calidad optimizado y escalado con -moz-transform:
Tamaño del lienzo en pixastic:
Supongo que esto significa que Firefox no está utilizando el muestreo bicúbico como se supone. Tendré que esperar hasta que realmente lo agreguen.
EDIT3:
¿Buscas otra gran solución simple?
var img=document.createElement(''img'');
img.src=canvas.toDataURL();
$(img).css("background", backgroundColor);
$(img).width(settings.width);
$(img).height(settings.height);
Esta solución utilizará el algoritmo de cambio de tamaño del navegador! :)
Acabo de publicar una página de comparaciones de lado a lado y, a menos que algo haya cambiado recientemente, no pude ver una mejor reducción de tamaño (escalado) utilizando canvas frente a css simple. He probado en FF6 Mac OSX 10.7. Todavía ligeramente suave contra el original.
Sin embargo, me topé con algo que hizo una gran diferencia y fue el uso de filtros de imagen en los navegadores que admiten lienzo. En realidad, puede manipular imágenes como Photoshop con desenfoque, nitidez, saturación, ondulación, escala de grises, etc.
Luego encontré un increíble complemento de jQuery que simplifica la aplicación de estos filtros: http://codecanyon.net/item/jsmanipulate-jquery-image-manipulation-plugin/428234
Simplemente aplico el filtro de nitidez justo después de cambiar el tamaño de la imagen, lo que le dará el efecto deseado. Ni siquiera tuve que usar un elemento canvas.
Algo interesante que encontré hace un tiempo mientras trabajaba con un lienzo que podría ser útil:
Para cambiar el tamaño del control de Canvas por sí mismo, debe usar los atributos height=""
y width=""
(o canvas.width
/ canvas.height
elements). Si usa CSS para cambiar el tamaño del lienzo, realmente estirará (es decir, redimensionará) el contenido del lienzo para que se ajuste al lienzo completo (en lugar de simplemente aumentar o disminuir el área del lienzo).
Valdría la pena intentarlo dibujando la imagen en un control de lienzo con los atributos de alto y ancho configurados al tamaño de la imagen y luego usando CSS para cambiar el tamaño del lienzo al tamaño que está buscando. Tal vez esto usaría un algoritmo de cambio de tamaño diferente.
También se debe tener en cuenta que el lienzo tiene diferentes efectos en diferentes navegadores (e incluso diferentes versiones de diferentes navegadores). Es probable que los algoritmos y las técnicas utilizadas en los navegadores cambien con el tiempo (especialmente con Firefox 4 y Chrome 6 que saldrán tan pronto, lo que pondrá un gran énfasis en el rendimiento del renderizado del lienzo).
Además, es posible que también desee darle un tiro a SVG, ya que probablemente también use un algoritmo diferente.
¡La mejor de las suertes!
Convertí la respuesta de @ syockit así como el enfoque de reducción gradual en un servicio Angular reutilizable para cualquiera que esté interesado: https://gist.github.com/fisch0920/37bac5e741eaec60e983
Incluí ambas soluciones porque ambas tienen sus pros / contras. El enfoque de convolución de lanczos es de mayor calidad al costo de ser más lento, mientras que el enfoque de reducción escalonada produce resultados razonablemente suavizados y es significativamente más rápido.
Ejemplo de uso:
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
})
})
El problema con algunas de estas soluciones es que acceden directamente a los datos de píxeles y los recorren en bucle para realizar el submuestreo. Dependiendo del tamaño de la imagen, esto puede requerir muchos recursos y sería mejor utilizar los algoritmos internos del navegador.
La función drawImage () está utilizando un método de remuestreo del vecino más cercano de interpolación lineal. Eso funciona bien cuando no redimensionas más de la mitad del tamaño original .
Si hace un bucle para cambiar solo el tamaño máximo de la mitad a la vez, los resultados serían bastante buenos y mucho más rápidos que acceder a los datos de píxeles.
Esta función reduce la muestra a la mitad a la vez hasta alcanzar el tamaño deseado:
function resize_image( src, dst, type, quality ) {
var tmp = new Image(),
canvas, context, cW, cH;
type = type || ''image/jpeg'';
quality = quality || 0.92;
cW = src.naturalWidth;
cH = src.naturalHeight;
tmp.src = src.src;
tmp.onload = function() {
canvas = document.createElement( ''canvas'' );
cW /= 2;
cH /= 2;
if ( cW < src.width ) cW = src.width;
if ( cH < src.height ) cH = src.height;
canvas.width = cW;
canvas.height = cH;
context = canvas.getContext( ''2d'' );
context.drawImage( tmp, 0, 0, cW, cH );
dst.src = canvas.toDataURL( type, quality );
if ( cW <= src.width || cH <= src.height )
return;
tmp.src = dst.src;
}
}
// The images sent as parameters can be in the DOM or be image objects
resize_image( $( ''#original'' )[0], $( ''#smaller'' )[0] );
Créditos a esta publicación.
Entonces, ¿qué haces si todos los navegadores (en realidad, Chrome 5 me dio uno bastante bueno) no te dan la calidad de remuestreo suficiente? ¡Tú mismo los implementas entonces! Oh, vamos, estamos entrando en la nueva era de la Web 3.0, los navegadores compatibles con HTML5, los compiladores JIT JavaScript súper optimizados, las máquinas de múltiples núcleos (†), con un montón de memoria, ¿a qué le teme? Oye, está la palabra java en javascript, así que eso debería garantizar el rendimiento, ¿verdad? He aquí, el código generador de miniaturas:
// 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";
};
... con el que puedes producir resultados como estos!
De todos modos, aquí hay una versión ''fija'' de tu ejemplo:
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);
};
¡Ahora es el momento de probar sus mejores navegadores y ver cuál es el que menos aumentará la presión arterial de su cliente!
Umm, ¿dónde está mi etiqueta de sarcasmo?
(ya que muchas partes del código se basan en Anrieff Gallery Generator , ¿también están cubiertas por la GPL2? No lo sé)
† En realidad, debido a la limitación de javascript, no se admite el multi-núcleo.
Esta es una función javascript adaptada del código de @Telanor. Cuando se pasa una imagen base64 como primer argumento a la función, devuelve la base 64 de la imagen redimensionada. maxWidth y maxHeight son opcionales.
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();
}
Gracias @syockit por una respuesta impresionante. Sin embargo, tuve que volver a formatear un poco como sigue para que funcione. Quizás debido a problemas de escaneo DOM:
$(document).ready(function () {
$(''img'').on("load", clickA);
function clickA() {
var img = this;
var canvas = document.createElement("canvas");
new thumbnailer(canvas, img, 50, 3);
document.body.appendChild(canvas);
}
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(process1, 0, this, 0);
}
//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;
}
}
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(process1, 0, self, u);
else
setTimeout(process2, 0, self);
};
process2 = function (self) {
self.canvas.width = self.dest.width;
self.canvas.height = self.dest.height;
self.ctx.drawImage(self.img, 0, 0);
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";
}
});
He puesto algunos algoritmos para hacer la interpolación de imágenes en arreglos de píxeles de lienzo html que podrían ser útiles aquí:
http://jsperf.com/pixel-interpolation/2
Se pueden copiar / pegar y se pueden usar dentro de los trabajadores web para cambiar el tamaño de las imágenes (o cualquier otra operación que requiera interpolación, las estoy usando para eliminar las imágenes en este momento).
No he agregado las cosas de lanczos arriba, así que siéntase libre de agregar eso como una comparación si lo desea.
Le sugiero que revise este enlace y se asegure de que esté configurado como verdadero.
Controlar el comportamiento de la escala de la imagen.
Presentado en Gecko 1.9.2 (Firefox 3.6 / Thunderbird 3.1 / Fennec 1.0)
Gecko 1.9.2 introdujo la propiedad mozImageSmoothingEnabled en el elemento canvas; Si este valor booleano es falso, las imágenes no se suavizarán al escalarlas. Esta propiedad es verdadera por defecto. ver en papel
- cx.mozImageSmoothingEnabled = false;
Obtuve esta imagen haciendo clic derecho en el elemento del lienzo en Firefox y guardando como.
var img = new Image();
img.onload = function () {
console.debug(this.width,this.height);
var canvas = document.createElement(''canvas''), ctx;
canvas.width = 188;
canvas.height = 150;
document.body.appendChild(canvas);
ctx = canvas.getContext(''2d'');
ctx.drawImage(img,0,0,188,150);
};
img.src = ''original.jpg'';
De todos modos, aquí hay una versión ''fija'' de tu ejemplo:
var img = new Image();
// added cause it wasnt defined
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
var canvasCopy = document.createElement("canvas");
// adding it to the body
document.body.appendChild(canvasCopy);
var copyContext = canvasCopy.getContext("2d");
img.onload = function()
{
var ratio = 1;
// defining cause it wasnt
var maxWidth = 188,
maxHeight = 150;
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;
// the line to change
// ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
// the method signature you are using is for slicing
ctx.drawImage(canvasCopy, 0, 0, canvas.width, canvas.height);
};
// changed for example
img.src = ''original.jpg'';
Para cambiar el tamaño de la imagen con un ancho menor que el original, uso:
function resize2(i) {
var cc = document.createElement("canvas");
cc.width = i.width / 2;
cc.height = i.height / 2;
var ctx = cc.getContext("2d");
ctx.drawImage(i, 0, 0, cc.width, cc.height);
return cc;
}
var cc = img;
while (cc.width > 64 * 2) {
cc = resize2(cc);
}
// .. than drawImage(cc, .... )
y funciona =).
Prueba pica : es un tamaño altamente optimizado con algoritmos seleccionables. Ver demo .
Por ejemplo, la imagen original de la primera publicación cambia de tamaño en 120ms con el filtro Lanczos y la ventana de 3px o 60ms con el filtro de Box y la ventana de 0.5px. Para una gran imagen de 17 MB de 5000 x 3000 píxeles, el tamaño toma ~ 1 en el escritorio y 3 en el móvil.
Todos los principios de cambio de tamaño se describieron muy bien en este hilo, y pica no agrega ciencia espacial. Pero está optimizado muy bien para los JIT-s modernos, y está listo para usar fuera de la caja (a través de npm o bower). Además, utiliza trabajadores web cuando están disponibles para evitar que la interfaz se bloquee.
También planeo agregar pronto el soporte de máscara de enfoque, porque es muy útil después de bajar de escala.
Rápido tamaño de la imagen / algoritmo de remuestreo utilizando el filtro Hermite con JavaScript. Transparencia de apoyo, da buena calidad. Avance:
Actualización : se agregó la versión 2.0 en GitHub (más rápido, trabajadores web + objetos transferibles). ¡Finalmente lo tengo funcionando!
Git: https://github.com/viliusle/Hermite-resize
Demostración: 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);
}
Resizer de la imagen de Javascript rápido y simple:
https://github.com/calvintwr/Hermite-resize
Utilizar:
h.resize({
source: document.getElementById(''image''), // any canvas or image elements, jQuery or native
width: 400,
height: 600,
output: ''image'', // [optional] `image` or `canvas`. If not entered output is same as input element.
quality: 0.7, // [optional] applicable for `image` output only
}, function(output) {
//your callback
});
Historia
Esto es realmente después de muchas rondas de investigación, lectura y ensayo.
El algoritmo de cambio de tamaño utiliza el script Hermite de @ ViliusL (el cambio de tamaño de Hermite es realmente el más rápido y ofrece un resultado razonablemente bueno). Ampliado con las características que necesita.
Forks 1 worker hace el cambio de tamaño para que no se congele el navegador al cambiar el tamaño, a diferencia de todos los otros resansores de JS que hay.
Sé que este es un hilo antiguo, pero podría ser útil para algunas personas como yo que meses después están abordando este problema por primera vez.
Aquí hay un código que cambia el tamaño de la imagen cada vez que recargas la imagen. Soy consciente de que esto no es óptimo en absoluto, pero lo ofrezco como una prueba de concepto.
Además, lamento el uso de jQuery para los selectores simples, pero me siento muy cómodo con la sintaxis.
$(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>
Se llama a mi función createImage una vez cuando se carga el documento y después se llama cada vez que la ventana recibe un evento de cambio de tamaño.
Lo probé en Chrome 6 y Firefox 3.6, ambos en la Mac. Esta "técnica" se come al procesador como si fuera helado en el verano, pero funciona.
Si simplemente está tratando de cambiar el tamaño de una imagen, recomendaría configurar el width
y el height
de la imagen con CSS. Aquí hay un ejemplo rápido:
.small-image {
width: 100px;
height: 100px;
}
Tenga en cuenta que la height
y el width
también se pueden configurar utilizando JavaScript. Aquí está el ejemplo de código rápido:
var img = document.getElement("my-image");
img.style.width = 100 + "px"; // Make sure you add the "px" to the end,
img.style.height = 100 + "px"; // otherwise you''ll confuse IE
Además, para garantizar que la imagen redimensionada se vea bien, agregue las siguientes reglas css al selector de imágenes:
-
-ms-interpolation-mode: bicubic
: introducir en IE7 -
image-rendering: optimizeQuality
: introducido en FireFox 3.6
Por lo que puedo decir, todos los navegadores, excepto IE, utilizan un algoritmo bicúbico para cambiar el tamaño de las imágenes de forma predeterminada, por lo que las imágenes con el nuevo tamaño deberían verse bien en Firefox y Chrome.
Si la configuración del width
y height
css no funciona, es posible que desee jugar con una transform
css:
Si, por alguna razón, necesita usar un lienzo, tenga en cuenta que hay dos formas de cambiar el tamaño de una imagen: redimensionando el lienzo con css o dibujando la imagen en un tamaño más pequeño.
Vea esta pregunta para más detalles.
¡Espero que esto ayude!
Tengo la sensación de que el módulo que escribí producirá resultados similares a Photoshop, ya que conserva los datos de color promediando, no aplicando un algoritmo. Es un poco lento, pero para mí es lo mejor, porque conserva todos los datos de color.
https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js
No toma al vecino más cercano y suelta otros píxeles, ni muestra un grupo y toma un promedio aleatorio. Toma la proporción exacta que cada píxel de origen debe enviar al píxel de destino. El color de píxel promedio en la fuente será el color de píxel promedio en el destino, y estas otras fórmulas, creo que no lo serán.
un ejemplo de cómo usarlo se encuentra en la parte inferior de https://github.com/danschumann/limby-resize
ACTUALIZACIÓN OCT 2018 : En estos días mi ejemplo es más académico que cualquier otra cosa. Webgl es bastante 100%, por lo que sería mejor cambiar el tamaño con eso para producir resultados similares, pero más rápido. PICA.js hace esto, creo. -