After iOS 11, Apple’s camera defaulted to the HEIC format, which reportedly significantly reduces photo size without compromising quality. You can check this in 设置-相机-格式, where “High Efficiency” refers to HEIC format and “Most Compatible” refers to the original JPEG format. For more details on HEIC, see here.
The issue this raises is that no web browsers currently support displaying HEIC images, making conversion a necessity.
I often drag or copy-paste photos directly from Apple’s Photos app into Craft. However, uploading such images to a personal blog won’t display them unless converted to a universal format like PNG or JPEG. Here, I chose to use the Sharp library for conversion, opting for WebP (since HEIC-to-PNG results in excessively large files).
Converting common formats like JPEG to PNG is straightforward, but HEIC poses challenges because Sharp relies on a platform-native tool called libvips:
Without this tool globally installed locally, processing HEIC images will trigger the following error:
1 2 3 4 5
(node:11469) UnhandledPromiseRejectionWarning: Error: source: bad seek to 807962 heif: Unsupported feature: Unsupported codec (4.3000)
(Use `node --trace-warnings ...` to show where the warning was created) (node:11469) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
It states that HEIC files cannot be processed.
The first step in troubleshooting is checking the official repository’s issues, where I found similar problems:
sharp: Using cached /Users/x/.npm/_libvips/libvips-8.13.3-darwin-x64.tar.br sharp: Integrity check passed for darwin-x64 npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN test2@1.0.0 No description npm WARN test2@1.0.0 No repository field.
added 45 packages from 206 contributors and audited 45 packages in 4.5s
10 packages are looking for funding run `npm fund` for details
found 0 vulnerabilities
After deleting the cached directory rm -rf /Users/x/.npm/_libvips/ mentioned in the logs and retrying, the system version of libvips still wasn’t utilized:
sharp: Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.13.3/libvips-8.13.3-darwin-x64.tar.br sharp: Integrity check passed for darwin-x64 npm notice created a lockfile as package-lock.json. You should commit this file. npm WARN test2@1.0.0 No description npm WARN test2@1.0.0 No repository field.
added 45 packages from 206 contributors and audited 45 packages in 10.727s
10 packages are looking for funding run `npm fund` for details
found 0 vulnerabilities
I decided to debug the package.
Starting with the logs, I searched for version-checking keywords like Using cached in the node_modules/sharp package, finding relevant code in sharp/install/libvips.js:
1
libvips.log(`Using cached ${tarPathCache}`);
Further investigation revealed a function determining whether to use the system’s built-in libvips or its own pre-compiled binary (which lacks HEIC support):
This was the crux. Debugging showed that the check for isRosetta returned true. If it returned false, the system’s libvips would be used instead:
A peculiar observation during debugging: process.arch output x64, while logging this code showed sysctl.proc_translated: 1:
Yet, executing the same code directly in the console output sysctl.proc_translated: 0:
Here I concluded that it must be a Node version issue causing it to use its own compiled libvips. So I used nvm to switch the default Node version to the arm64 version, then ran npm i sharp again, and the problem was resolved.
Below is the code that might be used in this process:
However, the author explained that there was a reason for the function’s current implementation. So I suggested that they add a warning during Sharp installation to inform users why the globally installed libvips package wasn’t being used. Eventually, the author accepted my suggestion:
I often wish that when facing some key decisions in life, someone could tell me the best course of action so that I would not waste my precious time. Putting myself in others' shoes, I therefore write blogs often, hoping to record in this tiny corner of the vast Internet the once-in-a-lifetime experiences that matter to me, and to help those who seek help.