2011-04-08 18 views
5

Actualmente estoy desarrollando una extensión mozilla, tratando de cargar una imagen (PNG) que está codificada con un URI de datos, dibujarlo en un elemento canvas, para finalmente cambiar algunos píxeles valores y guardarlo de nuevo como un archivo en el disco.javascript canvas.toDataURL cambios en comparación con los datos originales URI

Lo extraño que noto es que incluso si no cambio nada en la imagen y solo dibujo la imagen en el lienzo y el uso de canvas.toDataURL() para ver qué se genera, esta información codificada es diferente del original.

El código que estoy usando para ver esto es bastante básico:

var image = new Image(); 
image.onload = function() { 
    var canvas = document.createElement('canvas') 
    canvas.width = image.width; 
    canvas.height = image.height; 
    canvas.getContext('2d').drawImage(image, 0, 0); 
    var data = canvas.toDataURL(); // this right here is different from image.scr data! 
} 
image.src = "data:image/png;base64," + encodedData; 

que suponer que hay algún tipo de compresión o puede ser algo relacionado con transparencias pasando.

He comprobado the documentation pero no he podido encontrar la explicación. Creo que vi algo sobre algunos colores cambiando a otros similares, y eso podría ser lo que está jugando con lo que quiero lograr (es decir, cambiar algunos valores de píxeles).

¿Alguna idea de lo que está pasando?

Si no, ¿alguien sabe si hay alguna otra forma de guardar la imagen de lienzo en un archivo en el disco sin utilizar el método toDataURL? ¿Puede ser un componente XPCOM capaz de guardar todos los píxeles en formato binario PNG?

Gracias

+0

He probado que a pesar de la URI de datos es diferente , si creo una nueva imagen cargando este nuevo URI de datos resultante de toDataURI, cuando obtengo los datos de imagen con: 'imageData = canvas.getContext ('2d'). getImageData (0, 0, canvas.width, canvas.height); 'ambos son iguales y los píxeles parecen tener los mismos valores. ¿Cómo puede ser esto posible? – sagar38

Respuesta

0

Hay una variedad de legal ways to losslessly filter and encode PNG. Por ejemplo, mire this chart mostrando las enormes diferencias de tamaño de archivo posibles al codificar sin pérdidas la misma imagen con diferentes herramientas.

Me sorprendería, sin embargo, si vuelve a dibujar la versión toDataURL en el lienzo y obtiene un nuevo toDataURL y es diferente. Esperaría que el mismo navegador codificara la misma imagen de manera idéntica cada vez.

1

Hay un caso particular que he encontrado donde se han cambiado los píxeles. Puede haber más casos. No puedo ofrecer una explicación técnica en profundidad, por lo tanto, no puedo decir que en realidad no cambie la imagen.

Si establece el valor alfa en algo menor que 255 (1.0), entonces los demás componentes de ese píxel parecen alterarse. Una solución para el problema era simplemente establecer todos los valores alfa en 255.

A partir de este momento, puedo almacenar datos de precisión exactos en Canvas utilizando ImageData y un elemento DOM de imagen y luego recuperar estos mismos datos exactos con no hay pérdida configurando el componente alfa en 255 y no usándolo para almacenar datos.

Estas son las rutinas que actualmente estoy usando:

function make_image_with_data(contents) { 
    // Fractional side length. 
    var fside = Math.sqrt(contents.length/3); 
    // Whole integer side length. 
    var side = Math.ceil(fside); 

    var cv = document.createElement('canvas'); 

    cv.width = side; 
    cv.height = side; 

    var ctx = cv.getContext('2d'); 
    var id = ctx.createImageData(side, side); 

    var data = id.data; 

    data[0] = (contents.length >> 24) & 0xff; 
    data[1] = (contents.length >> 16) & 0xff; 
    data[2] = (contents.length >> 8) & 0xff; 
    data[3] = 255; 
    data[4] = (contents.length) & 0xff; 

    var z = 5; 
    var x = 0; 

    for (; x < contents.length; ++x) { 
     data[z] = contents.charCodeAt(x); 
     // Skip the image alpha component. 
     ++z; 
     if (z % 4 == 3) { 
      data[z] = 255; 
      ++z; 
     } 
    } 

    ctx.putImageData(id, 0, 0); 

    var img = document.createElement('img'); 
    img.width = side; 
    img.height = side; 

    img.src = cv.toDataURL(); 

    $(document.body).append(img); 

    return img; 
} 

Entonces la función para obtener los datos de nuevo fuera es:

function load_data_from_image(img) { 
    var cv = document.createElement('canvas'); 
    cv.width = img.width; 
    cv.height = img.height; 
    var ctx = cv.getContext('2d'); 

    ctx.drawImage(img, 0, 0, img.width, img.height); 

    var id = ctx.getImageData(0, 0, img.width, img.height); 
    var data = id.data; 

    var len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[4]; 
    var out = new Uint8Array(new ArrayBuffer(len)); 

    var z = 5; 

    for (var x = 0; x < len; ++x) { 
     out[x] = data[z]; 
     // This is skipping the alpha component. 
     ++z; 
     if (z % 4 == 3) { 
      ++z; 
     } 
    } 

    return out; 
} 
Cuestiones relacionadas