Copiar un div y enviarlo al portapapeles

En este artículo vamos a explicar cómo copiar un div y enviarlo al portapapeles, para después pegarlo con (Ctrl + V, «pegar») en Word, Excel, etc. En un foro se planteó la pregunta si era posible copiar un div y enviarlo al portapapeles, para después pegarlo con (Ctrl + V, «pegar») en un Word, Excel, etc. Tengo que reconocer que esta pregunta me intrigó muchísimo y enseguida me motivó a buscar una respuesta.

En principio, si sólo pensamos en términos HTML parece que no es posible. Pero si seguimos profundizando en la cuestión, descubrimos que tenemos elementos como el <canvas> que nos permiten crear gráficos en la web. Buscando por Internet encontré la librería html2canvas que nos hace el trabajo sucio. Con una sola instrucción es capaz de transformar un elemento HTML y todo su contenido en una imagen <canvas>. Ya tenemos medio camino hecho !!

Ahora llega el inconveniente, copiar la imagen <canvas> con el típico copy/paste de cualquier editor. Esto que parece sencillo, en un entorno web es algo más complicado. La imagen que se ha creado con <canvas> se interpreta como cualquier otra imagen en la web. La podemos manipular con el menú del botón derecho del ratón, ver en nueva pestaña, descargar, etc. pero esto no es lo que buscamos.

Queremos que un «clic» nos copie un elemento HTML en el portapapeles y un Ctrl + V o «pegar» lo pegue en un editor tipo Word

Así que después de varias pruebas di con la solución: La API blob y la API clipboard 🙂

La API Blob nos premite transformar la imagen <canvas> en un objeto de datos que puede representar cualquier tipo de fichero, como por ejemplo un archivo png de imagen.

La API clipboard nos permite copiar datos en el portapapeles, el tipo de datos que queremos copiar será nuestra imagen <canvas> transfromada en un blob.

Problemas al copiar

  • Los datos blob, que representan nuestra imagen, se interpretan como un archivo de nuestro disco duro local y JavaScript tiene prohibido acceder a los archivos locales por temas de seguridad
  • La API clipboard no funciona en todos los navegadores, por ejemplo en Firefox primero debe activarse una variable interna por temas de seguridad, cosa que los usuarios desconocen

Soluciones al copiado

  • El código sólo funciona en entorno de servidor, ya sea en nuestra web subida a Internet o en nuestro servidor local WAMP, XAMP, etc. Esto significa que una vez subida nuestra web sí funcionará 😉
  • El código sólo funciona de forma estándar en Chrome y Edge. Esto lo podemos detectar e informar desde nuestra web

Copiar div y enviarlo al portapapeles

Podemos crear webs capaces de copiar un div y enviarlo al portapapeles, informando que sólo está disponible para Chrome y Edge. En nuestras pruebas locales debemos usar un servidor local.

Una vez explicado todo el proceso teórico y la investigación que he llevado a cabo hasta dar con la solución, vamos a la explicación práctica del código. Imaginemos que queremos crear una web con partes del código HTML que puedan ser copiadas como una imágen tal que así:

  <div class="toClipboard" style="width:50%; background:#f5da55" onclick="copyToClipboard(this)">
    <h1>HTML TO CLIPBOARD</h1>
    <p>Ejemplo de cómo transformar elementos HTML en imágen y copiarla al portapapeles</p>
  </div>
  <div class="toClipboard" style="background:#55c2f5" onclick="copyToClipboard(this)">
    <h2>Otro DIV</h2>
    <p>Con un poco<br>de texto</p>
    <img src="imagen.jpg"/>
    <p>y una imagen por en medio ...</p>
  </div>

Tenemos dos <div> diferentes con unos estilos específicos para diferenciarlos y ambos tienen diferentes elementos como títulos, textos, imágenes, etc.

Como son elementos HTML que el usuario puede copiar con un «click» de ratón los podemos distinguir con una clase CSS específica, en mi caso llamada class='toClipboard', de forma que el usuario pueda identificar fácilmente estos elementos «copiables».

La forma de ejecutar nuestra función de copia sobre un elementos HTML será añadiendo un evento onclick='copyToClipboard(this)', donde simplemente llamamos a nuestra función de copia con el elemento que queremos copiar.

Para que todo esto funcione en nuestra función de copia hacemos lo siguiente:

    function copyToClipboard(element) {
      html2canvas(element).then(canvas => {
        canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})]));
      });
    };

La librería html2canvas hace todo el trabajo de copiado con simplemente pasarle el elemento HTML y nos devuelve una variables llamada canvas que contiene todos los textos, estilos, imágenes, etc. del elemento HTML transformado en una imagen <canvas>, fantástica librería !!

La instrucción navigator.clipboard.write([new ClipboardItem({'image/png': blob})]); es muy específica y debe escribirse de esta manera, sirve para copiar el conjunto de datos blob al portapapeles.

Con las nuevas sintaxis JavaScript casi parece arte de magia que en apenas 3 lineas consigamos hacer tantas cosas, pero podemos desglosar el código en partes y trabajar con las diferentes variables para crear más efectos o funciones en nuestra web. De modo que podemos reescribir nuestra función de copia de la siguiente manera:

    function copyToClipboard(element) {
      // Llamada a la librería
      html2canvas(element).then(canvas => {
        // Podemos añadir un mensaje de elemento copiado
        alert("Copiado !!\nCtrl + V para pegar"); 
        // Podemos añadir la imagen al final de la página para que pueda ser descargada
        document.body.appendChild(canvas);
        // Tranformamos imagen <canvas> en formato de datos blob
        canvas.toBlob(function(blob) {
          // Aquí podemos seguir trabajando el blob
          console.log('Este es el blob: ', blob);
          // Copiamos el blob al portapapeles como datos de imagen
          navigator.clipboard.write([new ClipboardItem({'image/png': blob})]);
        });
      });
    }; 

Ahora podemos trabajar tanto con la variable canvas que contiene una imagen, como mostrar mensajes, etc. En algunas situaciones además de un copy/paste nos puede interesar guardar la imagen como un archivo png y de esta forma lo podemos hacer.

Si alguno quiere seguir trabajando el blob también puede añadir sus lineas de código antes de copiarlo en el clipboard.

A continuación pongo todo el código HTML con las cabeceras y enlaces a la librería html2canvas, pero en este ejemplo no pongo la detección de los navegadores compatibles Chrome/Edge por pereza 😉

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>HTML TO CLIPBOARD</title>
  <script src="html2canvas.min.js"></script>
  <style>
    .toClipboard {
      padding: 1em;
      border: 4px solid black;
    }
    .toClipboard:hover {
      border: 4px solid red;
    }
  </style>
  <script>
    function copyToClipboard(element) {
      html2canvas(element).then(canvas => {
        canvas.toBlob(blob => navigator.clipboard.write([new ClipboardItem({'image/png': blob})]));
      });
    };
  </script>
</head>

<body>
  <div class="toClipboard" style="width:50%; background:#f5da55" onclick="copyToClipboard(this)">
    <h1>HTML TO CLIPBOARD</h1>
    <p>Ejemplo de cómo transformar elementos HTML en imágen y copiarla al portapapeles</p>
  </div>
  <div class="toClipboard" style="background:#55c2f5" onclick="copyToClipboard(this)">
    <h2>Otro DIV</h2>
    <p>Con un poco<br>de texto</p>
    <img src="imagen.jpg"/>
    <p>y una imagen por en medio ...</p>
  </div>
</body>
</html>

Ahora ya podemos abrir un Word, Paint o cualquier otro editor y ser capaces de copiar un div y enviarlo al portapapeles para pegarlo como una imagen con un simple Ctrl + V o el comando pegar.

Referencias:

¡ Espero que este artículo sea de vuestro interés !

Deja un comentario