A few things to note to get this working properly.
First, in windows the assigned mime type for heic and heif is blank. Not sure when this bug will get fixed, but for now you can't rely on mime type in your scripts or input tag. I needed to add the heic and heif file extensions in the accept parameter of my input tag:
<input type="file" accept="image/*,.heic,.heif" />
and in my script I created a function to check the file extension for heic and heif if mime type was blank.
function isHEIC(file) { // check file extension since windows returns blank mime for heic
let x = file.type ? file.type.split('image/').pop() : file.name.split('.').pop().toLowerCase();
return x == 'heic' || x == 'heif';
}
Also, heic2any is pretty large (even if minified and compressed). I decided to load it dynamically only when needed.
function loadScript(url, callback) {
var script = document.querySelectorAll('script');
for (var i = 0; i < script.length; i++) {
if (script[i].src === url) {
script = script[i];
if (!script.readyState && !script.onload) {
callback();
} else { // script not loaded so wait up to 10 seconds
var secs = 0, thisInterval = setInterval(function() {
secs++;
if (!script.readyState && !script.onload) {
clearInterval(thisInterval);
callback();
} else if (secs == 10) {
clearInterval(thisInterval);
console.log('could not load ' + url);
}
}, 1000);
}
return;
}
}
script = document.createElement('script');
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
if (script.readyState) {
script.onreadystatechange = function() {
if (script.readyState === 'loaded' || script.readyState === 'complete') {
script.onreadystatechange = null;
callback();
}
}
} else {
script.onload = function() {
script.onload = null;
callback();
}
}
script.src = url;
}
I my use case I'm leveraging heic2any to prepare images for upload. If the image is heic I convert it to png (blob), then pass the result to another utility (image blob reduce) to resize and sharpen before converting to jpg in preparation for upload. However, for the sake of simplicity the example below uses heic2any to convert to jpg in 1 step before upload.
function convertHEIC(file) {
return new Promise(function(resolve) {
if (!isHEIC(file)) return resolve(file);
loadScript('https://cdn.jsdelivr.net/npm/heic2any@0.0.3/dist/heic2any.min.js', function() {
heic2any({
blob: file,
toType: "image/jpg"
}).then(function (convertedFile) {
convertedFile.name = file.name.substring(0, file.name.lastIndexOf('.')) + '.jpeg';
resolve(convertedFile);
});
});
});
}
// convert any heic (and do any other prep) before uploading the file
convertHEIC(file).then(function(file) {
// code to upload (or do something else with file)
.
.
.
}