¿Cómo funciona la función de pegar imagen del portapapeles en Gmail y Google Chrome 12+?

148

Noté una publicación de blog de Google que menciona la capacidad de pegar imágenes directamente desde el portapapeles en un mensaje de Gmail si está utilizando la última versión de Chrome. Probé esto con mi versión de Chrome (12.0.742.91 beta-m) y funciona muy bien usando las teclas de control o el menú contextual.

A partir de ese comportamiento, debo suponer que la última versión de webkit utilizada en Chrome puede manejar imágenes en el evento de pegado de Javascript, pero no he podido encontrar ninguna referencia a dicha mejora. Creo que ZeroClipboard se une a eventos de pulsación de teclas para activar su funcionalidad flash y, como tal, no funcionaría a través del menú contextual (también, ZeroClipboard es un navegador cruzado y la publicación dice que esto solo funciona con Chrome).

Entonces, ¿cómo funciona esto y dónde se realizó la mejora de Webkit (o Chrome) que permite la funcionalidad?

Emil Lerch
fuente
3
Parece que también funciona aleatoriamente con Firefox. ¿Alguien sabe si se supone que esto es compatible con Firefox?
Sébastien

Respuestas:

231

Pasé un tiempo experimentando con esto. Parece seguir la nueva especificación API del Portapapeles . Puede definir un controlador de eventos "pegar" y mirar event.clipboardData.items, y llamar a getAsFile () para obtener un Blob. Una vez que tenga un Blob, puede usar FileReader para ver qué contiene . Así es como puede obtener una URL de datos para las cosas que acaba de pegar en Chrome:

// window.addEventListener('paste', ... or
document.onpaste = function(event){
  var items = (event.clipboardData || event.originalEvent.clipboardData).items;
  console.log(JSON.stringify(items)); // will give you the mime types
  for (index in items) {
    var item = items[index];
    if (item.kind === 'file') {
      var blob = item.getAsFile();
      var reader = new FileReader();
      reader.onload = function(event){
        console.log(event.target.result)}; // data url!
      reader.readAsDataURL(blob);
    }
  }
}

Una vez que tenga una URL de datos, puede mostrar la imagen en la página. Si desea cargarlo en su lugar, puede usar readAsBinaryString, o puede ponerlo en un XHR usando FormData .

Nick Retallack
fuente
66
Agarrando pajitas aquí, pero ¿alguna idea de por qué event.clipboardData.items parece estar 'indefinido' en Safari 5.1? ¿O incluso cómo obtener el contenido del portapapeles para un archivo / blob en Safari? Funciona muy bien en Chrome. Uno pensaría que habría WebKit WebKit :(
Gavin Gilmour
77
@SenicaGonzalez eso se debe a que los datos solo existen durante la duración del evento. Después del evento, desaparece, por lo que cuando intente abrir el objeto en el inspector no verá nada.
Nick Retallack
3
ejecuto esto en Firefox y var blob = items [0] .getAsFile () throw TypeError: los elementos no están definidos
chinna_82
2
¿Le importaría hacer un ejemplo de cómo enviar una XMLHttpRequest con esos datos de imagen? Eso sería realmente agradable: D
poitroae
1
Así es como puede enviar eso utilizando XMLHttpRequest, lo escribí en un blog después de implementarlo: blog.securevideo.com/2013/11/27/…
JT Taylor
56

La respuesta de Nick parece necesitar pequeños cambios para seguir funcionando :)

// window.addEventListener('paste', ... or
document.onpaste = function (event) {
  // use event.originalEvent.clipboard for newer chrome versions
  var items = (event.clipboardData  || event.originalEvent.clipboardData).items;
  console.log(JSON.stringify(items)); // will give you the mime types
  // find pasted image among pasted items
  var blob = null;
  for (var i = 0; i < items.length; i++) {
    if (items[i].type.indexOf("image") === 0) {
      blob = items[i].getAsFile();
    }
  }
  // load image if there is a pasted image
  if (blob !== null) {
    var reader = new FileReader();
    reader.onload = function(event) {
      console.log(event.target.result); // data url!
    };
    reader.readAsDataURL(blob);
  }
}

Código de ejecución de ejemplo: http://jsfiddle.net/bt7BU/225/

Entonces, los cambios en la respuesta de nicks fueron:

var items = event.clipboardData.items;

a

var items = (event.clipboardData  || event.originalEvent.clipboardData).items;

También tuve que tomar el segundo elemento de los elementos pegados (el primero parece ser text / html si copia una imagen de otra página web en el búfer). Entonces cambié

  var blob = items[0].getAsFile();

a un bucle que encuentra el elemento que contiene la imagen (ver arriba)

No sabía cómo responder directamente a la respuesta de Nick, espero que esté bien aquí: $ :)

robintibor
fuente
1
¿Cómo debemos enviar los datos de la imagen como XMLHttpRequest?
poitroae
Para otros que lean esto, la respuesta a esta pregunta puede incluirse allí ahora: stackoverflow.com/questions/18055422/… :)
robintibor
44
No entiendo. Cuando pego archivos en el navegador, clipboardData.itemssiempre está vacío en Google Chrome (Firefox funciona). El Chrome ahora necesita casi tanta optimización como solía tener IE.
Tomáš Zato - Restablece a Monica el
1
Edición pequeña: if (blob! = Null) {(o establecer blob = null en la inicialización)
Pancakeo
1
event.clipboardData.itemsfuncionó bien para mí en el último Chrome, ¿no está seguro de cuándo event.originalEvent...es útil?
Ruben Martinez Jr.
5

Los navegadores web siguen avanzando. Recientemente encontré esto:

Fragmento de código: acceso a imágenes del portapapeles con Javascript

y esto:

The Paste Wasteland (o, por qué el evento onPaste es un desastre)

El primer enlace describe una forma de obtener imágenes del portapapeles usando JavaScript solo en Firefox y Chrome. El segundo enlace contiene una posdata que menciona que la misma técnica fue adaptada a IE (versión desconocida).

Rich Apodaca
fuente
Firefox ni siquiera activa Editar | Pegue el elemento del menú para mí, por lo que no veo cómo funciona en Firefox en absoluto.
podperson
Cualquiera de esos enlaces no funciona al momento de comentar.
Crazywako
2

Por lo que sé -

Con las funciones de HTML 5 (File Api y las relacionadas), ahora es posible acceder a los datos de la imagen del portapapeles con JavaScript simple.

Sin embargo, esto no funciona en IE (nada menos que IE 10). No sé mucho sobre el soporte de IE10 también.

Para IE, los optiens que creo que son las opciones de 'respaldo' están usando la API de AIR de Adobe o usando un applet firmado

saurshaz
fuente
1

Wow eso es genial. Todavía no me he sumergido en la fuente de Gmail para resolverlo (lo hice con la funcionalidad de arrastrar), pero supongo que es una extensión de la API de arrastrar / soltar que Chrome ya ha extendido. Hay una descripción decente sobre cómo funciona la función de arrastrar al escritorio: http://www.thecssninja.com/javascript/gmail-dragout que al menos puede orientarlo en la dirección correcta.

Mark Kahn
fuente
0

Esto es de un ejemplo con el mecanografiado angular2 que funciona para mi proyecto. Espero que ayude a alguien. La lógica es igual para otros casos también.

https://gist.github.com/sandeepsuvit/a8ba77faebba260455985504be24aef7

Aquí hay una implementación en vivo:

https://stackblitz.com/edit/angular-f7kcny?file=app/app.component.ts

Sandeep K Nair
fuente
1
¿Podría explicar qué proceso siguió? Puede abrir el enlace https://stackblitz.com/edit/angular-f7kcny?file=app/app.component.tsen Chrome y luego hacer clic derecho en una imagen de cualquier sitio web. Luego péguelo en el cuadro de texto proporcionado. Debería funcionar de esa manera.
Sandeep K Nair
copiado de trabajos de imagen web. Intenté imágenes del explorador de Windows, por eso no funcionaba entonces. ¿Conoces alguna forma de manejar la imagen copiada del explorador de Windows para pegarla en la página web?
Battle Hawk
No he probado esta opción todavía. Esperemos que se puede obtener una amplia perspectiva de estas bibliotecas en cambio https://github.com/layerssss/paste.js/, https://github.com/JoelBesada/pasteboard. Hay demostraciones disponibles en estos enlaces que puede probar.
Sandeep K Nair
event.clipboardData está vacío cuando pegué la imagen en máquinas con sistema operativo Windows. ¿Alguien puede explicar por qué sucede esto?
Tunç Doğan