开发者的 HEIC 转 JPG 方案:云 API、自建与浏览器端

发布于

只要你的应用接收 iPhone 拍的照片,就会收到 HEIC 文件,而大多数浏览器显示不了它。把 HEIC 转成 JPG 有三类做法:交给云端 API、在自己的服务器上跑解码库、在用户浏览器里解码后只上传 JPG。三者最大的区别是原图会去哪里。下面依据各项目自己的文档逐一对比,核对日期为 2026 年 10 月 31 日。

三类方案一览

方案 HEIC 在哪里解码 例子 要确认的事
云端 API 服务商的服务器 CloudConvert API、Cloudinary 文件会上传到服务商并由其存储
自建服务 你自己的服务器 libheif、ImageMagick、libvips / sharp 编译版本必须带 HEVC 解码器
浏览器端 用户自己的设备 heic-to、heic2any、libheif-js 库的体积、用户设备的 CPU 与内存、元数据

云端 API

**CloudConvert API。**处理以「任务(job)」为单位,一个任务由几步组成:导入文件、转换、导出结果。CloudConvert 公开的格式列表里,heic 转 jpg 使用 imagemagick 引擎,每次消耗 1 个 credit。最简单的任务用 POST https://api.cloudconvert.com/v2/jobs 提交:

{
  "tasks": {
    "import-my-file": { "operation": "import/url", "url": "https://example.com/photo.heic" },
    "convert-my-file": { "operation": "convert", "input": "import-my-file", "input_format": "heic", "output_format": "jpg" },
    "export-my-file": { "operation": "export/url", "input": "convert-my-file" }
  }
}

import/upload 这一步可以让用户把文件直接传给 CloudConvert,不经过你的服务器。它的隐私政策写明,文件会传输到 CloudConvert 的服务器并临时存储;API 文档写明,任务结束 24 小时后自动删除。处理区域可以固定为 eu-central(德国)或 us-east(美国弗吉尼亚)。

**Cloudinary。**Cloudinary 的格式表把 HEIF(.heif、.heic)列为支持上传、支持变换。做法是先把原图上传到你的 Cloudinary 账户,再按另一种格式请求它:文档说需要固定格式时用 f_jpg,Cloudinary 会把图片转换为请求的格式再交付。

无论用哪家,原图都会离开你的基础设施,由服务商存储。本文不写价格:两家都按套餐或 credit 计费,我们没有核实当前价格。

自建服务

libheif 是几乎所有处理 HEIC 的开源应用都在用的 HEIF 库。它的 README 写明:HEIC 解码默认用 libde265,编码用 x265,而 x265 是 GPL 许可;libheif 本身是 LGPL。自带的 heif-dec 命令会把 HEIF 文件里的每一张图都转换出来:

heif-dec photo.heic photo.jpg

Python(pillow_heif、pyheif)、Go、Rust、.NET、Node.js 都有绑定。README 还提到,仅 2026 年就调查并修复了 89 个安全公告,所以如果要解码用户上传的文件,记得及时更新。

ImageMagick 能读写 HEIC,但格式表注明 HEIC 需要 libheif 委托库(原文 Requires libheif delegate library)。先用 magick -list format 确认你的版本支持,再转换:

magick photo.heic -quality 90 photo.jpg

**Node.js 的 sharp(基于 libvips)。**sharp 的预编译版本支持 JPEG、PNG、Ultra HDR、WebP、AVIF、TIFF、GIF 和 SVG(仅输入)。对 iPhone 照片这种 HEVC 压缩的 HEIC,sharp 在 heif() 输出选项的文档里要求使用全局安装、编译时带 libheif、libde265 和 x265 的 libvips。我们在 Mac 上用预编译的 sharp 0.35.4 试了一张 1200 万像素的 iPhone 7 照片:metadata() 能读出 heif 和 hevc,但转 JPEG 时报错 heif: Decoder plugin generated an error。也就是说,元数据检查通过的文件,照样可能解码失败。

只在 Mac 上,系统自带的 sips 命令不用安装任何东西就能转换。在 macOS 26 上,它把同一张照片转成了 4032×3024 的 JPG,并保留了 Exif:

sips -s format jpeg -s formatOptions 90 photo.heic --out photo.jpg

heif-dec 和 magick 我们没有实际运行,因为测试机上没有安装;命令按官方文档写成。

浏览器端

在浏览器里解码,服务器自始至终只收到 JPG。代价是要加载一个很大的脚本,转换也占用用户设备的 CPU 和内存。

库 许可证(npm) 最新版本 README 中的要点
heic-to LGPL-3.0 1.6.7,2026-10-27 跟进 libheif 新版本;Web Worker 里用 heic-to/next,严格 CSP 下用 heic-to/csp
heic2any MIT 0.0.4,2023-03-29 只能在浏览器里用;不复制元数据
libheif-js LGPL-3.0 1.23.5,2026-10-04 用 Emscripten 编译的 libheif,可用于 Node.js 和浏览器;底层解码 API

heic-to 的 README 给出的调用方式:

import { heicTo } from "heic-to"

const jpeg = await heicTo({ blob: file, type: "image/jpeg", quality: 0.9 })

我们在 Chromium 里用 heic-to 1.5.2 对那张 iPhone 7 照片做了同样的调用,得到一张 4032×3024、1,494,239 字节的 JPEG,里面没有 Exif。需要拍摄时间或方向信息的话,得自己写回去。

heicly 是怎么做的

heicly 是一个网页,不提供 API。它在 Web Worker 里调用 heic-to 1.5.2:先把照片解码成 ImageBitmap,再画到 OffscreenCanvas 上,这一步同时纠正方向,并把超过 16,777,216 像素的大图按比例缩小;然后编码成 JPG,默认质量 90。最近一次转换的画布会缓存下来,拖动质量滑块时只重新编码,不再解码。拍摄时间和相机信息会写回 JPG,拍摄位置只有用户打开选项后才保留。

怎么选

  • **已经在用媒体云服务:**云端 API 最省事,前提是你的隐私政策允许把用户照片上传给该服务商。
  • **文件只能留在自己的服务器:**用带 HEVC 解码的 libheif、ImageMagick 或 libvips,并保持更新。
  • **希望原图留在用户设备上:**在浏览器里转换,只上传 JPG。记得用大照片在低端手机上测试。

先看看浏览器端的效果

想先看看浏览器端转换的效果?直接试下面的转换器。它在本页运行,照片不会上传。

将 HEIC 或 HEIF 照片拖到这里

或者

你的文件不会离开这台设备——转换全程在浏览器里完成。转换过一次后,断网也能用。

可一次选择多张 HEIC 或 HEIF 照片。超大照片可能会被缩小以适应浏览器限制;在手机上转换大量照片时,建议分批进行。

    注意:刷新或关闭页面会清除当前任务和结果。

    想了解格式本身,可以看 HEIC 和 JPG 的区别 和 照片格式指南。

    来源

    2026 年 10 月 31 日核对:CloudConvert 的 API 简介、Jobs、导入文件、格式列表与隐私政策;Cloudinary 的支持格式、图片优化与上传 API;libheif README;ImageMagick 的格式表与命令行选项;sharp 的安装说明与输出选项;npm 上的 heic-to、heic2any 与 libheif-js。

    ← 全部文章