Skip to content

Instantly share code, notes, and snippets.

@jagomf
Last active September 29, 2018 17:28
Show Gist options
  • Save jagomf/cb1f42245259a957c4247765d4234325 to your computer and use it in GitHub Desktop.
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)
/**
* 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