2009-06-01 15 views
291

Tengo una página HTML normal con algunas imágenes (solo etiquetas regulares <img /> HTML). Me gustaría obtener su contenido, codificado en base64 de preferencia, sin la necesidad de volver a descargar la imagen (es decir, ya está cargada por el navegador, así que ahora quiero el contenido).¿Obtener datos de imagen en JavaScript?

Me encantaría lograr eso con Greasemonkey y Firefox.

Respuesta

374

Nota: Esto sólo funciona si la imagen es del mismo dominio que la página, o tiene el atributo crossOrigin="anonymous" y el servidor soporta CORS. Tampoco le proporcionará el archivo original, sino una versión recodificada. Si necesita que el resultado sea idéntico al original, consulte Kaiido's answer.


Usted tendrá que crear un elemento de lienzo con las dimensiones correctas y copiar los datos de la imagen con la función drawImage. Luego puede usar la función toDataURL para obtener una información: url que tiene la imagen codificada en base 64. Tenga en cuenta que la imagen debe estar completamente cargada, o simplemente obtendrá una imagen vacía (negra, transparente).

Sería algo como esto. Nunca escribí un script de Greasemonkey, por lo que es posible que deba ajustar el código para que se ejecute en ese entorno.

function getBase64Image(img) { 
    // Create an empty canvas element 
    var canvas = document.createElement("canvas"); 
    canvas.width = img.width; 
    canvas.height = img.height; 

    // Copy the image contents to the canvas 
    var ctx = canvas.getContext("2d"); 
    ctx.drawImage(img, 0, 0); 

    // Get the data-URL formatted image 
    // Firefox supports PNG and JPEG. You could check img.src to 
    // guess the original format, but be aware the using "image/jpg" 
    // will re-encode the image. 
    var dataURL = canvas.toDataURL("image/png"); 

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); 
} 

conseguir una imagen con formato JPEG no funciona en versiones anteriores (alrededor de 3.5) de Firefox, así que si usted quiere apoyar eso, usted tendrá que comprobar la compatibilidad. Si la codificación no es compatible, se establecerá de forma predeterminada en "image/png".

+1

Si bien esto parece estar funcionando (excepto el no protegido/en el retorno), no crea la misma cadena base64 que la que obtengo de PHP cuando se hace base64_encode en el archivo obtenido con la función file_get_contents. Las imágenes parecen muy similares/iguales, aún el de Javascripted es más pequeño y me encantaría que fueran exactamente iguales. Una cosa más: la imagen de entrada es una pequeña (594 bytes), 28x30 PNG con fondo transparente, si eso cambia algo. – Detariael

+0

También http://www.motobit.com/util/base64-decoder-encoder.asp confirma que la cadena codificada en Base64 de JavaScript es incorrecta: si se crea a partir del archivo original, el resultado es el mismo que el mío de PHP y diferente de el de Javascript. – Detariael

+7

Firefox podría estar usando un nivel de compresión diferente que afectaría la codificación. Además, creo que PNG admite información de encabezado adicional, como notas, que se perderá, ya que el lienzo solo obtiene los datos de píxeles. Si necesita que sea exactamente igual, probablemente pueda usar AJAX para obtener el archivo y base64 codificarlo manualmente. –

66

Esta función toma la URL a continuación, devuelve la BASE64 imagen

function getBase64FromImageUrl(url) { 
    var img = new Image(); 

    img.setAttribute('crossOrigin', 'anonymous'); 

    img.onload = function() { 
     var canvas = document.createElement("canvas"); 
     canvas.width =this.width; 
     canvas.height =this.height; 

     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(this, 0, 0); 

     var dataURL = canvas.toDataURL("image/png"); 

     alert(dataURL.replace(/^data:image\/(png|jpg);base64,/, "")); 
    }; 

    img.src = url; 
} 

llamada así: getBase64FromImageUrl("images/slbltxt.png")

+8

¿Hay alguna forma de convertir una imagen de un enlace externo a la base 64? – dinodsaurus

+0

@dinodsaurus puede cargarlo en una etiqueta de imagen, o hacer una consulta de AJAX. –

+0

Obtengo una imagen incompleta haciendo esto. ¿Tienes alguna idea de por qué? – AimanB

22

Además de Mateo respuesta, me gustaría decir que image.width e imagen .height devuelve el tamaño mostrado de la imagen (y recorta la imagen al dibujarla en el lienzo)

Use naturalWidth y naturalHeight en su lugar, que utiliza la imagen de tamaño real.

Ver http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#dom-img-naturalwidth

+1

que me ayudó ... ¡Estaba pensando por qué mi única parte de mi imagen se carga cada vez! – hashcoder

+0

¿Cómo es esta una respuesta? Esto debería ser una edición o un comentario, si me preguntas –

24

Coming mucho después, pero ninguna de las respuestas aquí son del todo correcto.

Cuando se dibuja en un lienzo, la imagen pasada se descomprime + todo pre-multiplicado.
Cuando se exporta, se descomprime o recomprime con un algoritmo diferente y no se multiplica.

Todos los navegadores y dispositivos tendrán diferentes errores de redondeo en este proceso
(ver Canvas fingerprinting).

Así que si uno quiere una versión base64 de un archivo de imagen, tiene que solicitar de nuevo (la mayoría de las veces proviene de la memoria caché) pero esta vez como un Blob.

Luego puede usar un FileReader para leerlo como ArrayBuffer o como dataURL.

function toDataURL(url, callback){ 
 
    var xhr = new XMLHttpRequest(); 
 
    xhr.open('get', url); 
 
    xhr.responseType = 'blob'; 
 
    xhr.onload = function(){ 
 
     var fr = new FileReader(); 
 
    
 
     fr.onload = function(){ 
 
     callback(this.result); 
 
     }; 
 
    
 
     fr.readAsDataURL(xhr.response); // async call 
 
    }; 
 
    
 
    xhr.send(); 
 
} 
 

 
toDataURL(myImage.src, function(dataURL){ 
 
    result.src = dataURL; 
 

 
    // now just to show that passing to a canvas doesn't hold the same results 
 
    var canvas = document.createElement('canvas'); 
 
    canvas.width = myImage.naturalWidth; 
 
    canvas.height = myImage.naturalHeight; 
 
    canvas.getContext('2d').drawImage(myImage, 0,0); 
 

 
    console.log(canvas.toDataURL() === dataURL); // false - not same data 
 
    });
<img id="myImage" src="https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png" crossOrigin="anonymous"> 
 
<img id="result">

+0

Acabo de pasar por más de 5 preguntas diferentes y tu código es el único que funcionó correctamente, gracias :) – Peter

+0

Me aparece este error con el código anterior. 'XMLHttpRequest no puede cargar datos: image/jpeg; base64,/9j/4AA .../2Q ==. Respuesta invalida. Por lo tanto, el origen 'https://example.com' no está permitido. ' – STWilson

+1

@STWilson, sí, este método también está vinculado a la política de origen idéntico, al igual que el lienzo. En caso de solicitud de origen cruzado, debe configurar el servidor de alojamiento para permitir tales solicitudes de origen cruzado a su secuencia de comandos. – Kaiido

0

function encodeImageFileAsURL(cb) { 
 
    return function() { 
 
     var file = this.files[0]; 
 
     var reader = new FileReader(); 
 
     reader.onloadend = function() { 
 
      cb(reader.result); 
 
     } 
 
     reader.readAsDataURL(file); 
 
    } 
 
} 
 

 
$('#inputFileToLoad').change(encodeImageFileAsURL(function(base64Img) { 
 
    $('.output') 
 
     .find('textarea') 
 
     .val(base64Img) 
 
     .end() 
 
     .find('a') 
 
     .attr('href', base64Img) 
 
     .text(base64Img) 
 
     .end() 
 
     .find('img') 
 
     .attr('src', base64Img); 
 
}));
@import url('//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css'); body{ padding: 20px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<h2>Input</h2> 
 
<form class="input-group" id="img2b64"> 
 
    <input id="inputFileToLoad" type="file" onchange="encodeImageFileAsURL();" /> 
 
</form> 
 
<hr>
Aquí está Working Fiddle Ejemplo: - upload & get Image Data

+0

dio algunas posibles razones. ¿Fue una de esas razones? ¿O algo mas? Podría ser útil para futuros lectores entender cuál era el problema subyacente – core114

+0

@ core114 ​​Me encontré con este mismo problema, así que he creado un nuevo violín para este tipo de problema si es incorrecto. Por favor, háganme saber que eliminaré esta respuesta. :-) –

+0

@PathRaval No elimine su respuesta, me refiero a su respuesta mejor con información :) por ejemplo: mire la respuesta de kaiido – core114

Cuestiones relacionadas