Estoy desarrollando una pequeña aplicación web con un renderizador de tres js donde quiero poder almacenar algunas capturas de pantalla en mi sistema de archivos local en una ubicación específica. Renderizar las imágenes y crear las instantáneas funciona, solo la parte de almacenamiento/descarga me da dolor de cabeza.
Creo la instantánea de esta manera:
let imageData = renderer.domElement.toDataURL('image/png'); console.log(imageData); // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABFAAAANBC... Ahora, para descargar esto, existen varios métodos: window.location.href = imageData; desencadena una descarga (y varios mensajes de alerta del navegador). Pero la imagen descargada se almacena como un archivo llamado descarga dentro de la carpeta de descargas. Si se agrega la extensión de archivo .png , se puede abrir. Esta no es una solución útil, difícilmente se asignarán varias descargas seguidas.
Entonces, otro método de trabajo es crear un enlace de descarga y activar su método de clic:
let a_element = document.createElement('a'); a_element.setAttribute('href', imageData.replace('image/png', 'image/octet-stream'); a_element.setAttribute('download', 'screenshot.png'); a_element.style.display = 'none'; document.body.appendChild(a_element); a_element.click(); document.body.removeChild(a_element);Esto descarga la captura de pantalla con un nombre personalizado en la carpeta Descargar, es casi lo que quiero, pero también me gustaría tenerlos almacenados en una carpeta personalizada. Ahí es donde entra la API del sistema de archivos. El inconveniente es que cada descarga debe confirmarse, pero no tener que mover los archivos manualmente desde la carpeta de descarga valdría la pena.
const options = { types: [ { description: 'Images', accept: { 'image/png': ['.png'], }, }, ], suggestedName: 'Screenshot.png', }; imgFileHandle = await window.showSaveFilePicker(options); console.log("Save File chosen"); const writable = await imgFileHandle.createWritable(); await writable.write(imageData); await writable.close();Esto parece funcionar, pero el archivo que se almacena no es una imagen válida. Contiene solo texto (igual que la salida de la consola). ¿Cómo debo tratar el imageData para descargarlo como una imagen?
Para la API de acceso al sistema de archivos, casi ha llegado, pero en lugar de una URL de datos, debe proporcionar los datos como un blob. Para crear un blob a partir de una URL de datos, puede usar el siguiente código:
function dataURItoBlob(dataURI) { const byteString = atob(dataURI.split(',')[1]); const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0] const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } const blob = new Blob([ab], {type: mimeString}); return blob; } Puede ser más fácil obtener el Blob directamente, a través del método toBlob() . Esto también debería funcionar en Three.js, ya que renderer.domElement es un CanvasElement .