const regFileExtension = /(?:\.([^.]+))?$/; export class FileUtil { static getExtension(fileName: string): string | undefined { return regFileExtension.exec(fileName)[1]; } static getExtensions(fileList: FileList): string[] { const extensions: string[] = []; // tslint:disable-next-line: prefer-for-of for (let i = 0; i < fileList.length; i++) { extensions.push(FileUtil.getExtension(fileList[i].name)); } return extensions; } static fromBlobToDataUrl(blob: Blob): Promise { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = () => { return resolve(fileReader.result); }; fileReader.onerror = (event: ProgressEvent) => { fileReader.abort(); return reject(fileReader.error); }; fileReader.readAsDataURL(blob); }); } static fromBlobToBuffer(blob: Blob): Promise { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onloadend = () => { return resolve(Buffer.from(fileReader.result as ArrayBuffer)); }; fileReader.onerror = (event: ProgressEvent) => { fileReader.abort(); return reject(fileReader.error); }; fileReader.readAsArrayBuffer(blob); }); } static fromDataUrlToFile(fileNameAppender: string, dataUrl: string): File { const BASE64_MARKER = ';base64,'; // tslint:disable-next-line: variable-name const isDataURI = (_url: string) => _url.split(BASE64_MARKER).length === 2; if (!isDataURI(dataUrl)) { return undefined; } const mime = dataUrl.split(BASE64_MARKER)[0].split(':')[1]; const filename = fileNameAppender + new Date().getTime() + '.' + mime.split('/')[1]; const bytes = atob(dataUrl.split(BASE64_MARKER)[1]); const writer = new Uint8Array(new ArrayBuffer(bytes.length)); for (let i = 0; i < bytes.length; i++) { writer[i] = bytes.charCodeAt(i); } return new File([writer.buffer], filename, { type: mime }); } static fromBlobToString(blob: Blob): Promise { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = () => { return resolve(fileReader.result.toString()); }; fileReader.onerror = (event: ProgressEvent) => { fileReader.abort(); return reject(fileReader.error); }; fileReader.readAsArrayBuffer(blob); }); } static downloadFromBlob(blob: Blob, fileName: string) { const a = document.createElement('a'); document.body.appendChild(a); a.style.display = 'none'; const url = URL.createObjectURL(blob); a.href = url; a.download = fileName; a.click(); window.URL.revokeObjectURL(url); a.remove(); } static save( buffer: Buffer, fileName: string, mimeType: string ): Promise { return new Promise((resolve, reject) => { const defaultMime = 'application/octet-stream'; const mime = !!mimeType ? mimeType : defaultMime; const blob = new Blob([buffer], { type: mime }); if (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL) navigator.msSaveBlob(blob, fileName); resolve(fileName); return; } const download = (url: string, mode: boolean = false) => { const anchor = document.createElement('a'); if ('download' in anchor) { // html5 A[download] anchor.href = url; anchor.setAttribute('download', fileName); anchor.className = 'download-js-link'; anchor.innerHTML = 'downloading...'; anchor.style.display = 'none'; document.body.appendChild(anchor); setTimeout(() => { anchor.click(); document.body.removeChild(anchor); resolve(fileName); if (mode) { setTimeout(() => { window.URL.revokeObjectURL(anchor.href); }, 250); } }, 66); return; } // handle non-a[download] safari as best we can: if ( /(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test( navigator.userAgent ) ) { url = url.replace(/^data:([\w\/\-\+]+)/, defaultMime); if (!window.open(url)) { // popup blocked, offer direct download: if ( confirm( 'Displaying New Document\n\nUse Save As... to download, then click back to return to this page.' ) ) { location.href = url; } } resolve(fileName); return; } // do iframe dataURL download (old ch+FF): const f = document.createElement('iframe'); document.body.appendChild(f); if (!mode) { // force a mime that will download: url = 'data:' + url.replace(/^data:([\w\/\-\+]+)/, defaultMime); } f.src = url; setTimeout(() => { document.body.removeChild(f); }, 333); }; if (window.URL) { download(window.URL.createObjectURL(blob), true); } else { if ( typeof blob === 'string' || (blob as any).constructor === this.toString ) { try { download( 'data:' + mime + ';base64,' + window.btoa((blob as any) as string) ); } catch (e) { download( 'data:' + mime + ';base64,' + encodeURIComponent((blob as any) as string) ); } } else { const fileReader = new FileReader(); fileReader.onload = () => { download(fileReader.result as string); }; fileReader.readAsDataURL(blob); } } }); } static thumbnail(file: File): Promise { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.onload = () => { const blob = new Blob([fileReader.result], { type: file.type }); const url = URL.createObjectURL(blob); const video = document.createElement('video'); const snapImage = () => new Promise((imgResolve, imgReject) => { const canvas = document.createElement('canvas'); // thumbnail image resize const width = video.videoWidth; const height = video.videoHeight; let resizeWidth = 0; let resizeHeight = 0; // max size const maxWidth = 320; const maxHeight = 320; if (width > maxWidth || height > maxHeight) { if (width > height) { resizeWidth = maxWidth; resizeHeight = Math.round((height * resizeWidth) / width); } else { resizeHeight = maxHeight; resizeWidth = Math.round((width * resizeHeight) / height); } } else { resizeWidth = width; resizeHeight = height; } canvas.width = resizeWidth; canvas.height = resizeHeight; canvas .getContext('2d') .drawImage(video, 0, 0, canvas.width, canvas.height); canvas.toBlob(imgBlob => { imgResolve(imgBlob); }); }); const timeupdate = () => { snapImage().then(imgBlob => { video.removeEventListener('timeupdate', timeupdate); video.pause(); resolve(new File([imgBlob], file.name)); }); }; video.onloadeddata = () => { snapImage().then(imgBlob => { video.removeEventListener('timeupdate', timeupdate); resolve(new File([imgBlob], file.name)); }); }; video.addEventListener('timeupdate', timeupdate); video.preload = 'metadata'; video.src = url; // Load video in Safari / IE11 video.muted = true; // tslint:disable-next-line: no-string-literal video['playsInline'] = true; video.crossOrigin = 'anonymous'; video.play().catch(e => reject(e)); }; fileReader.onerror = (event: ProgressEvent) => { fileReader.abort(); return reject(fileReader.error); }; fileReader.readAsArrayBuffer(file); }); } }