HEIC is Apple's own format to store high resolution images made with iOS cameras. But I would store on backend JPG, because HEIC is not displayed in most browsers, not even in Safari.
SOLUTION 1
I tried this for the conversion:
const buffer = Buffer.from(await file.arrayBuffer())
const d = heicConvert({ buffer, format: 'JPEG' })
const imgBase64 = btoa(
d.reduce((data, byte) => `${data}${String.fromCharCode(byte)}`, '')
)
but because I use Next.js it is not compatible with it.
Failed to compile.
./node_modules/libheif-js/libheif/libheif.js
Module not found: Can't resolve 'fs' in '/Users/janoskukoda/Workspace/tikex/portal/team/node_modules/libheif-js/libheif'
SOLUTION 2
I tried this also:
export default uploadImage
const buffer = await file.arrayBuffer()
const image = sharp(buffer)
const metadata = await image.metadata()
if (metadata.format === 'heic') {
// Convert the image to JPG
const jpgBuffer = await image.jpeg().toBuffer()
// Encode the JPG image as a base64 string
const imgBase64 = btoa(
jpgBuffer.reduce((data, byte) => `${data}${String.fromCharCode(byte)}`, '')
)
}
But I can not compile, seems sharp
is not recommended to use in client side.
Do you have any other way to do it?
Anyway idea comes here: https://itnext.io/tackling-iphone-or-ipad-images-support-in-browser-8e3e64e9aaa1
If you show me a solution uses serverless api, it is also ok. It is important file comes from html input element.
CodePudding user response:
Install the heic2jpeg library by running the following command in your terminal:
npm install heic2jpeg
Import the heic2jpeg library in your React component:
import heic2jpeg from 'heic2jpeg';
Convert the HEIC file to JPG by calling the convert method of the heic2jpeg library and passing in the HEIC file as an argument:
const jpegData = await heic2jpeg.convert(heicFile);
You can then use the jpegData to create a new JPG file or display it in an img element:
const jpegFile = new File([jpegData], 'image.jpg', { type: 'image/jpeg' });
// or
const imageElement = document.createElement('img');
imageElement.src = URL.createObjectURL(jpegFile);
document.body.appendChild(imageElement);
Note that the heic2jpeg library requires the canvas and process modules to be available in the global context, so you may need to include these modules in your application as well.
CodePudding user response:
Before getting to the answer: You can never trust data uploaded by a client — you must always validate/convert using a process that is not accessible by a user (a backend process) to ensure data validity: even if there are mechanisms in place to validate received network requests as coming from an authenticated user on your site, any user can still use developer tools to execute arbitrary JavaScript and send whatever kinds of network requests with whatever payloads that they want to.
Regarding iOS devices and getting JPEG instead of HEIF from a file input: You don't need to do this yourself — iOS can do it for you.
<input type="file">
elements support an accept
attribute that can be used to restrict the kinds of file media types that can be uploaded: read more at the Limiting accepted file types section of the MDN documentation article for <input type="file">
.
Below is an example which shows how to use that attribute. When an iOS user selects the input, they can choose to take a photo using their camera or select one from the photo library. iOS will perform the necessary file conversion to JPEG automatically in both of these cases (for example, even when a selected image from the photo library is in HEIF format). The example demonstrates this when you try it with an HEIF-encoded image on an iOS device:
const input = document.getElementById('image-upload');
const output = document.getElementById('output');
const updateDisplayedFileInfo = () => {
const file = input.files?.[0];
if (!file) {
output.textContent = 'No file selected';
return;
}
const dateModified = new Date(file.lastModified).toISOString();
const {name, size, type} = file;
const data = {
dateModified,
name,
size,
type,
};
const json = JSON.stringify(data, null, 2);
output.textContent = json;
};
input.addEventListener('change', updateDisplayedFileInfo);
updateDisplayedFileInfo();
pre { background-color: hsla(0, 0%, 50%, 0.1); padding: 0.5rem; } code { font-family: monospace; }
<input id="image-upload" type="file" accept="image/jpeg" />
<pre><code id="output"></code></pre>