Last active
September 29, 2018 17:28
-
-
Save jagomf/cb1f42245259a957c4247765d4234325 to your computer and use it in GitHub Desktop.
Retrieve files and convert to base64 upon clicking on something; if any of the files are images, they can be limited to a max size (in pixels)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Prompts to choose a file from filesystem, converts to base64 (in background), and returns base64 when conversion ends. | |
* @param {number} maxFileSize Maximum size of file. | |
* @param {boolean} multiple Indicates whether to accept one or more files. | |
* @param {string} contentType MIME type of media to require from filesystem (can be 'image/*', etc). | |
* @param {number} maxSize Maximum size (in pixels) that images' largest dimention (width or length) should have, or 0 to ignore. | |
* @param {string} finalMimeType Mime type of the resulting resized image. | |
* @param {string} source (For mobile devices only) If set to 'camera', tells device to capture image from camera. | |
* @returns {Promise} A Promise that resolves when files are read; rejects with error if files are heavier than allowed. | |
*/ | |
onClickSendMedia(maxFileSize, multiple = false, contentType = '*/*', maxSize = 0, finalMimeType = 'image/jpeg', source) { | |
return new Promise((resolve, reject) => { | |
// Create temporary input element | |
const element = document.createElement('input'); | |
// Assign properties to element. | |
element.removed = false; | |
element.type = 'file'; | |
element.id = 'addAttach'; | |
element.multiple = multiple; | |
element.accept = contentType; | |
if (source) { // Needed for file fetch to work on iOS | |
element.capture = source; | |
} | |
// Hide element | |
element.style.display = 'none'; | |
// Register what happens when element content has changed | |
element.addEventListener('change', ({ target }) => { | |
const filesObj = Array.from(target.files); | |
const allFilesFit = filesObj.every(file => file.size <= maxFileSize); | |
if (!allFilesFit) { | |
reject(`Files cannot be bigger than ${maxFileSize / (1024 * 1024)}MB.`); | |
} | |
const processes = filesObj.map(fileObj => new Promise(resolveInner => { | |
const webworkerReader = new FileReader(); | |
webworkerReader.onload = () => { | |
// if file is an image, resize to specified max dimension | |
if (fileObj.type.match(/image.*/) && maxSize > 0) { | |
const image = new Image(); | |
image.onload = () => { | |
// Resize the image | |
const canvas = document.createElement('canvas'); | |
let width = image.width, height = image.height; | |
if (width > height && width > maxSize) { | |
height *= maxSize / width; | |
width = maxSize; | |
} else if (height > maxSize) { | |
width *= maxSize / height; | |
height = maxSize; | |
} | |
canvas.width = width; | |
canvas.height = height; | |
canvas.getContext('2d').drawImage(image, 0, 0, width, height); | |
const base64str = canvas.toDataURL(finalMimeType); | |
resolveInner(base64str); | |
}; | |
image.src = webworkerReader.result; | |
// else read file as is | |
} else { | |
const base64Str = webworkerReader.result; | |
resolveInner(base64Str); | |
} | |
}; | |
webworkerReader.readAsDataURL(fileObj); | |
})); | |
Promise.all(processes).then(values => { | |
resolve(values); | |
}); | |
// Once file content is retrieved, destroy temporary input element | |
element.onblur = null; | |
if (!element.removed) { | |
element.removed = true; | |
element.remove(); | |
} | |
}); | |
// Append element to DOM. | |
document.querySelector('body').appendChild(element); | |
// Force click | |
element.click(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment