import { Promise as EmberPromise } from 'rsvp' /** * Provides functions and properties to deal with files * * @module file */ const downscaleFactor = 0.6 // default amount to shrink image by.. only if width param is not given /** * A list of supported image types that are accepted for uploading * @const imageTypes * @type {Array} */ export const imageTypes = ['image/gif', 'image/png', 'image/jpg', 'image/jpeg', 'image/gif', 'image/svg', 'image/bmp'] /* istanbul ignore next */ export function makeFileUrl(url: string, str: string) { if (str.startsWith('http')) return str else return url + str } /** * Returns a Blob from the given URL * @function getImageFromUrl * @param {String} url url to fetch file from * @param {Boolean} resize whether to resize received image or not * @return {Promise} {name: 'file', 'file': dataUrl} */ /* istanbul ignore next */ export function getImageFromUrl(url: string, responseType: string = 'blob' ) { if (!url) throw new Error('Fetching image from url failed because it did not receive the url parameter') return new EmberPromise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = responseType as XMLHttpRequestResponseType; xhr.onload = async () => { const blob = xhr.response blob.lastModifiedDate = new Date() blob.name = 'file' if (!imageTypes.includes(blob.type)) { throw new Error('Image of type ' + blob.type + ' received from ' + url + ' is not allowed') } resolve(blob) }; xhr.onerror = error => { reject(error) } xhr.send() }) } /** * Returns a resized dataUrl from the given File OR Blob OR DataURL * @function resizeImage * @param {File, Blob, String} file Original file as File, Blob or DataURL(base64). * @param {Number} width Target image width * @param {Number} height Target image height * @param {Number} quality Image compression as % 0-100 or decimal 0.0 - 1.0 default 50 (0.5) * @param {Boolean} keepAspectRatio Maintain image's aspect ratio on resize - default True * @return {Promise} resized Base64 DataUrl of the given file */ /* istanbul ignore next */ export function resizeImage(file: File | Blob, width: number | null = null, height: number | null = null, quality: number = 80, keepAspectRatio: boolean = true) { /*tslint:disable-line*/ return new EmberPromise((resolve, reject) => { // if(!width) throw new Error('Image resize failed because it did not receive the width parameter') if (!keepAspectRatio && !height) throw new Error('Image resize failed because it wanted to change the aspect ratio, but it did not receive the height parameter') const mime = file.type || 'image/jpeg' // we want quality to be decimal (like 0.5 for 50%) if (quality % 1 === 0) quality = Number((quality / 100).toFixed(2)) const reader = new FileReader() if (typeof file === 'string' ) { file = dataURLtoBlob(file) } reader.readAsDataURL(file) reader.onloadend = () => { const img = new Image() as any img.src = reader.result img.onload = () => { const canvas = document.createElement('canvas') // if we do not have a target width just downscale image by some amount if (!width) width = img.width * downscaleFactor // we calculate scaleFactor from image width to maintain aspect ratio const scaleFactor = width / img.width if (keepAspectRatio) height = img.height * scaleFactor canvas.width = width canvas.height = Number(height) const ctx = canvas.getContext('2d') ctx?.drawImage(img, 0, 0, width, Number(height)) // resolve canvas as dataURL resolve(canvas.toDataURL(mime, quality)) } } reader.onerror = (err: any) => { reject(err) } }) } /** * Transforms a base64 encoded string to a Blob * @function dataURLtoBlob * @param {String} dataurl Base64 * @param {String} filename Your desired filename (default = 'file') * @return {Blob} */ /* istanbul ignore next */ export function dataURLtoBlob(dataurl: string, filename = 'file') { const arr = dataurl.split(',') if (!arr) return null const mime = arr[0].match(/:(.*?);/)![1] const bstr = atob(arr[1]) let n = bstr.length const u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } const blob = new Blob([u8arr], {type: mime}) as any; blob.name = filename blob.lastModifiedDate = new Date() return blob } export default { imageTypes, makeFileUrl, getImageFromUrl, resizeImage, dataURLtoBlob }