ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CentOS 7.9 源码编译 ImageMagick 实现 JPEG/PNG 转 HEIC 完整指南

CentOS 7.9 源码编译 ImageMagick 实现 JPEG/PNG 转 HEIC 完整指南 真的为了在 CentOS 7.9 服务器上实现“JPEG/PNG 转 HEIC”这个功能我挠掉了不少头发。原因不是 ImageMagick 不好用而是 CentOS 仓库里的 ImageMagick 实在太老了默认不支持 HEIC 格式。我这次的需求很明确一台内网物理服务器要把大量产品图从 JPEG/PNG 转成 HEIC 归档既省存储空间又方便后续分发给 iPhone 端做展示。如果你也是运维或后端开发手头正好有 CentOS 7.9 机器需要处理 HEIC 图片这篇文章就是给你写的。先给你一句话结论CentOS 7.9 默认源里的 ImageMagick 版本是 6.7.8.9发布于 2013 年而 HEIC 是 2015 年以后才逐步普及的格式所以直接用convert a.jpg a.heic一定会报 “no encode delegate” 之类的错误。想解决只能自己动手编译一个带 HEIC 支持的 ImageMagick。下面我会把完整的编译过程、命令、参数和踩坑点全部摊开来写保证你能照着跑通。1. 为什么系统默认的 ImageMagick 干不了 HEIC 这件事1.1 CentOS 7.9 自带 ImageMagick 的版本限制CentOS 7.9 的生命周期很长但仓库里的软件版本基本停留在 2015 年之前。你执行yum list installed | grep ImageMagick就会看到默认装的是 ImageMagick 6.7.8.9。这个版本本身并不认识 HEIC 文件甚至不知道 HEIF 容器是什么。ImageMagick 要支持一种格式必须有对应的 delegate 库也就是说它要把编解码工作外包给 libheif 这类第三方库自己只负责图像数据的管道处理。如果你强行用老版本处理 HEIC常见的报错是这样的convert: no decode delegate for this image format HEIC error/constitute.c/ReadImage/508这里的 “decode delegate” 就是外部解码器插件。没有它ImageMagick 就算拿到一张 HEIC 图片也无法解析。反过来要输出 HEIC 文件还需要 “encode delegate”。默认仓库里两个 delegate 都没有所以第一反应是yum install此路不通。1.2 HEIC 的构成不只是“图片格式”刚接触 HEIC 的人容易把它理解成 PNG 或 JPEG 那样的单一格式实际不是。HEIC 是一个基于 HEIFHigh Efficiency Image File Format容器的文件里面承载的是 HEVCH.265编码的图像数据。你可以把 HEIF 理解成一个盒子盒子里的内容才是核心编码数据。HEIC 专用扩展名.heic是苹果公司对 HEIF 容器的一种具体应用约定。为什么我记得这么清楚因为编译配置的时候很容易踩坑ImageMagick 需要的是libheif库而 libheif 不能凭空工作它内部又依赖编码器和解码器。解码器一般用libde265编码器一般用x265。所以实际依赖链是ImageMagick - libheif - libde265 x265任何一环缺失最终都会表现为 ImageMagick 不支持 HEIC。这也是很多教程只说了一半的缘故装了 libheif但没装底层编解码库最后照样报错。简而言之如果你想在 CentOS 7.9 上让 ImageMagick 支持 HEIC就必须从最底层开始把这三层依赖全部搭好。1.3 为什么不用现成 RPM 或 Docker 镜像你可能会问找第三方 RPM 包不是更快吗我试过。因为 CentOS 7 已经进入维护期很多第三方源对新软件支持得很慢或者根本不提供编译好 HEIC 支持的 ImageMagick。至于 Docker 镜像如果机器在公网环境用 Docker 确实方便但我们这边是内网物理服务器设备上还要跑不少离线业务额外引一个容器运行时反而不划算。干脆源码编译一劳永逸而且编译出来的版本和功能完全可控。整个过程大约需要 20 到 40 分钟主要耗时在 x265 的编译环节完全可以接受。2. 开工前的准备依赖、目录与离线做法2.1 系统基线检查在开始编译之前先确认系统版本和架构cat /etc/redhat-release uname -m我这边输出的是CentOS Linux release 7.9.2009 (Core) x86_64如果你是在物理机安装系统时规划了 LVM建议给/usr/local留足空间。因为源码默认安装到/usr/local多个编译库加起来大约占几百 MB。如果不单独划分根分区也可能没问题但我在另一台机器上遇到过根分区快满的情况后面清理起来非常痛苦。如果你还没有装 CentOS 7.9可以考虑先下载一个对应的系统镜像边安装边准备。这里不打算展开系统的分区细节只说一个建议最少让/usr/local和/opt独立分区特别是/opt专门用来放源码包这样后续编译、升级和清理都比较安全。2.2 安装编译工具链源码编译需要完整的工具链。CentOS 7 上用yum groupinstall最省事yum install -y epel-release yum groupinstall -y Development Tools yum install -y cmake cmake3 autoconf automake libtool pkgconfig nasm这里特别说明几点Development Tools包含 gcc、gcc-c、make 等基础工具必须装。cmake3是给 x265 编译用的。CentOS 7 自带的 cmake 版本是 2.8.12虽然旧版 x265 可能能编但新版 x265 的构建脚本对 cmake 版本有要求直接用 EPEL 的 cmake3 能少踩很多坑。nasm是 x265 汇编优化所依赖的没有它编译也能过但编出来的库性能会明显下降建议装上。另外还要装图像处理相关的开发包让 ImageMagick 能正常读取 JPG、PNG、TIFF 等常见输入格式yum install -y libjpeg-turbo-devel libpng-devel libtiff-devel如果不装这些ImageMagick 虽然能把图片转成 HEIC但遇到 JPEG 输入时可能报 “no decode delegate for JPEG”那就非常尴尬。2.3 内网离线环境的源码包准备如果你的服务器不能直接访问外网现在这一步很关键。在一个能上网的机器上先到 GitHub 和 ImageMagick 官网把发布包下载好再上传到内网服务器。我自己习惯放到/opt/src目录打包传输过去。需要准备的有libde265 源码包x265 源码包libheif 源码包ImageMagick 源码包以我当时用的版本为例mkdir -p /opt/src cd /opt/src wget https://github.com/strukturag/libde265/releases/download/v1.0.11/libde265-1.0.11.tar.gz wget https://github.com/strukturag/libheif/releases/download/v1.16.2/libheif-1.16.2.tar.gz git clone https://bitbucket.org/multicoreware/x265_git.gitImageMagick 建议直接从官网归档目录下载稳定版cd /opt/src wget https://imagemagick.org/archive/ImageMagick.tar.gz注意版本号会变上面这些链接只是示例。离线场景下你完全可以下载好之后用 U 盘或内部跳板机移动到目标机器反正只要源码包完整编译过程不受影响。3. 编译 libde265 与 x265给 HEIC 装上前端引擎3.1 编译安装 libde265libde265 是解码库负责把 HEVC 编码的数据解码成图像。虽然我们的主要方向是“把 JPEG 转成 HEIC”也就是要编码但 libheif 在读取和验证 HEIC 文件时也离不开解码器所以 libde265 必须首先装好。进入源码目录按下面的步骤执行cd /opt/src tar xzf libde265-1.0.11.tar.gz cd libde265-1.0.11 ./autogen.sh ./configure --prefix/usr/local make -j$(nproc) make install ldconfig解释几个细节--prefix/usr/local指定安装路径这样后续其他库找它时都从标准路径找。-j$(nproc)表示用上所有 CPU 核心可以大幅缩短编译时间。nproc 是 Linux 命令用来获取 CPU 核数。如果你不确定可以先执行nproc看看手工写make -j8也行。ldconfig是刷新动态链接库缓存。CentOS 上如果你不执行后面 ImageMagick 运行时可能找不到libde265.so非常折磨人。实际操作时libde265 的编译时间很短几分钟内就结束了。如果autogen.sh提示缺少什么请回头检查第 2.2 步的工具链是否装齐。3.2 编译安装 x265x265 是编码库负责把图像编码成 HEVC 数据也就是真正产生 HEIC 内容的“发动机”。编译 x265 是整个流程里最慢的环节也是最容易出现版本兼容问题的一步。x265 的源码结构比较特殊我们需要进入它的构建目录cd /opt/src/x265_git/build/linux cmake3 ../../source make -j$(nproc) make install ldconfig为什么用cmake3因为 CentOS 7 自带的 cmake 是 2.8 版本x265 高版本会要求 2.8.12 以上而系统自带版本刚好踩线。用 EPEL 安装的 cmake3 更安全。如果你执行cmake3报命令不存在记得回头把yum install -y cmake3这一步补上。编译 x265 的时候机器会满载跑好一阵子我这边 8 核 CPU 编译大概花了 15 分钟。期间不要中断否则很难看出是卡住了还是正常编译。CPU 温度偏高的服务器建议适当降低-j参数改成make -j4虽慢一点但更稳定。3.3 验证底层库是否就位编译完不要急着做下一步先验证一下动态库是否被系统找到ls -l /usr/local/lib | grep 265 ldconfig -p | grep 265正常情况下能看到libde265.so和libx265.so的相关信息。如果ldconfig -p里搜不到说明/usr/local/lib没有在系统的动态库搜索路径中。可以执行echo /usr/local/lib /etc/ld.so.conf.d/local.conf ldconfig这一步是我后来加上的因为 CentOS 7 对/usr/local/lib的默认搜索策略并不总是可靠。4. 编译 libheif统一封装 HEIF/HEIC 格式4.1 configure 参数的选择libheif 是连接底层编解码器和 ImageMagick 的中间层。ImageMagick 通过它读写 HEIF/HEIC 文件然后它再调用 libde265 和 x265 完成具体的解码与编码任务。编译安装命令如下cd /opt/src tar xzf libheif-1.16.2.tar.gz cd libheif-1.16.2 ./autogen.sh ./configure --prefix/usr/local --with-libde265 --with-x265 make -j$(nproc) make install ldconfig--with-libde265和--with-x265是显式启用解码器和编码器。如果你只敲./configurelibheif 也能编但它有可能编译成不带编码支持的版本导致后续转 HEIC 失败。我建议在 configure 时直接检查输出看到类似 “enabled libde265: yes”、“enabled x265: yes” 的提示再继续。4.2 检查 pkg-config 路径libheif 安装完成后还要确保pkg-config能找到它因为 ImageMagick 的配置脚本依赖pkg-config来探测 libheif。如果 pkg-config 找不到ImageMagick 会静默禁用 HEIC delegate最终编译出来的版本还是不支持 HEIC。执行验证pkg-config --modversion libheif如果报错找不到包设置一下环境变量即可export PKG_CONFIG_PATH/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH你可以把这一行写进/etc/profile或~/.bashrc省得每次编译都手动设置。这算是我踩过最典型的坑之一前期编译全正常最后 ImageMagick 的--with-heic配置没有生效就是因为没有检查 pkg-config。5. 重编 ImageMagick开启 HEIC delegate5.1 源码编译与配置所有依赖库就位后终于到了重头戏。先把 ImageMagick 源码解压然后执行配置cd /opt/src tar xzf ImageMagick.tar.gz cd ImageMagick-7.* ./configure --prefix/usr/local --with-heicyes \ --with-jpegyes --with-pngyes --with-tiffyes \ --with-modules注意--with-heicyes是关键参数少了它编译出来的 ImageMagick 不包含 HEIC 支持。--with-modules是我个人习惯把格式解码器做成模块化加载后续加新格式更灵活。如果你不需要可以不加。配置脚本运行时最后会出现一段 delegate 支持汇总类似这样DELEGATES bzlib djvu fontconfig freetype heic jng jpeg lcms lzma png tiff webp xml zlib看到heic字样就说明配置成功。如果这里没有 heic就需要回头检查 libheif 是否装好、pkg-config 是否能找到 libheif。配置阶段还可能出现一个比较误导人的报错unrecognized option: --with-heic。这通常是因为你下载的 ImageMagick 版本太老或者不小心拿到 ImageMagick 6.x 的源码。CentOS 7 自带的老版本 ImageMagick 根本没有heic这个 configure 选项所以请务必从官网下载 7.x 版本。5.2 编译、安装与最终验证配置通过后执行编译和安装make -j$(nproc) make install ldconfig安装完成后用 ImageMagick 自己的命令验证格式支持/usr/local/bin/magick -list format | grep -i heic你会看到类似这样的输出HEIC HEIF rw- High Efficiency Image Format HEICS HEIF rw- High Efficiency Image Formatr代表可读w代表可写两个都有才是真的能输出 HEIC。如果只看到r--或者什么都没有说明编译配置有问题需要回到第 4 步检查。还要注意命令路径。CentOS 7 如果之前用 yum 装过 ImageMagick 6系统里会有一个/usr/bin/convert。而我们编译安装的 ImageMagick 7 在/usr/local/bin下。为了保证用的是新版直接使用magick命令或者显式指定/usr/local/bin/magick避免被 PATH 里旧版干扰。6. 转换命令、批量脚本与质量参数6.1 单张图片转换基础命令编译好之后转换命令非常简单magick input.jpg -quality 80 output.heic如果是多张图或尺寸很大的图建议先设置一个合理的输出尺寸再转 HEICmagick input.png -resize 1920x1080 -strip -quality 80 output.heic-strip表示去掉 EXIF、GPS 等元数据。归档场景如果有隐私需求这个参数很有用。如果你确实需要保留拍照时间等 EXIF 信息那就不要加-strip。-quality参数对 HEIC 的影响和 JPEG 类似默认值是 75 还是 80 我记不太清但我习惯手动指定。在视觉质量基本无损的情况下-quality 80是比较稳妥的选择。如果对画质要求高可以调到 90如果只是预览图调到 60 也能接受体积能进一步缩小很多。6.2 批量把 JPEG/PNG 转成 HEIC服务器上碰到的情况很少是单张图更多的是一个目录下几千张图。下面这个脚本是我实际用于归档的版本会保留目录结构并对失败文件单独记录日志#!/bin/bash SRC_DIR/data/upload DST_DIR/data/heic LOG_FILE/var/log/img2heic.log FAIL_LOG/var/log/img2heic-fail.log mkdir -p $DST_DIR find $SRC_DIR -type f \( -iname *.jpg -o -iname *.jpeg -o -iname *.png \) -print0 | \ while IFS read -r -d file; do rel${file#$SRC_DIR/} rel_dir$(dirname $rel) base$(basename $rel) name${base%.*} out$DST_DIR/$rel_dir/$name.heic mkdir -p $(dirname $out) if magick $file -strip -quality 80 $out 2$LOG_FILE; then echo OK: $file - $out else echo FAIL: $file $FAIL_LOG fi done脚本里有几个细节值得说find ... -print0配合while IFS read -r -d 是为了处理文件名中的空格和特殊字符。很多运维脚本在这里用for file in $(find...)遇到文件名带空格就会断掉我吃过亏。rel${file#$SRC_DIR/}是为了把源目录前缀去掉然后重新拼接到目标目录里保持目录结构一致。失败文件单独写进日志文件。几万张图的批量转换里总会有几张异常文件把它们单独记下来后面手工处理比看满屏输出要舒服得多。6.3 反向转换HEIC 转 JPEG既然你的服务器能读 HEIC 了那反向转换也很自然。比如 iPhone 拍的照片传到服务器需要做 Web 展示图可以这样magick IMG_1234.heic -resize 1920x1080 -quality 85 IMG_1234.jpg-quality 85对 JPEG 来说已经比较高质量肉眼几乎看不出区别但文件体积不会太夸张。如果不需要透明通道用 JPEG 输出没问题如果需要透明背景建议输出 PNG。7. 实际运行中遇到的问题与排查技巧我在编译和批量转换过程中大大小小的问题碰到不少。下面把几个高频问题整理成一个速查表方便你对照处理症状可能原因解决办法convert: no encode delegate for this image formatImageMagick 编译时未启用 HEIC用magick -list format检查 HEIC 支持重新编译configure: error: unrecognized option: --with-heic下载的是 ImageMagick 6.x 老版本到官网下载 7.x 稳定版源码error while loading shared libraries: libheif.so.1动态库缓存未刷新执行ldconfig或把/usr/local/lib写入/etc/ld.so.conf.d/local.confImageMagick 编译配置里没有 heicpkg-config 找不到 libheif执行export PKG_CONFIG_PATH/usr/local/lib/pkgconfig后重新 configure转换出来的 HEIC 无法打开libheif 未启用 x265或 libde265 未安装好重新编译 libheif加上--with-libde265 --with-x265验证底层库magick: not authorized或 policy 拒绝写文件ImageMagick 的 policy.xml 限制了 delegate编辑 policy.xml把 HEIC 相关条目设为 allowed或去掉限制批量转换中断部分文件生成 0 字节输入图片本身损坏或磁盘不足先看失败日志里的文件单独用magick identify诊断除了表格里的还有两个值得单独展开的坑。第一个是 ImageMagick 的 policy.xml。很多发行版出于安全考虑默认禁止了部分 delegate尤其是对远程 URL 和某些格式的读写。如果转换时提示“not authorized”你需要找到 ImageMagick 的 policy.xml。IM7 一般在/usr/local/etc/ImageMagick-7/policy.xml里面会看到类似下面这样的限制policy domaindelegate rightsnone patternURL / policy domaindelegate rightsnone patternHTTPS /处理办法是谨慎修改只对 HEIC 开白名单不要盲目把全部限制放开。保守设置的话可以直接在文件末尾加一行policy domaindelegate rightsread|write patternHEIC /加完保存再执行转换测试。注意如果机器对安全性有严格要求请先评估修改 policy.xml 造成的影响。第二个问题是输入文件格式异常。我碰过一张外表看起来是.jpg实际内容却是 PNG 的图ImageMagick 会根据文件头自动识别不会报错但我用脚本统一追加.heic后缀时部分处理结果出现颜色变化。这是因为 PNG 文件有透明通道转成 HEIC 时透明通道的处理和 JPEG 不完全一样。遇到透明图最好先统一转换到 RGB 空间再加白底。命令可以这样写magick input.png -background white -alpha remove -alpha off -quality 80 output.heic这里先指定白色背景再把 Alpha 通道去掉能避免黑底或透明信息错乱的问题。如果你的业务不需要保留透明推荐加上这两步。8. 一点经验和后续扩展建议编译这套东西本身不算难难的是中途千万不要自作聪明跳过验证步骤。我后来复盘整个流程最值得记住的就三件事一是确保底层库ldconfig刷新二是确保 pkg-config 能找到 libheif三是 configure 之后一定要看一眼 delegate 汇总里有没有 heic。只要这三步不出错基本一次能成。另外提醒一下HEIC 虽然省空间但不是所有平台都能无缝展示。Windows 上如果没有 HEIF 图像扩展它连缩略图都看不到老一点的浏览器也默认不支持 HEIC。所以生产环境里我通常的策略是“双轨并行”原始图片转成 HEIC 做冷备归档对外展示仍保留一份 JPEG 或 WebP。这样既不牺牲兼容性又能享受 HEIC 带来的存储红利。如果你后续还想折腾有几个方向可以试试一是把 ImageMagick 和 libheif 打包成 RPM这样其他服务器直接用yum localinstall就能装不用每台机器都编译一遍二是接入 GraphicsMagick 或者 vips 这类更轻量的库批量处理性能会更好三是写一个简单的systemd定时任务把/data/upload目录下新增的图片自动转成 HEIC 并移动到归档目录实现全自动化。我自己的下一步是把这套流程集成到对象存储上传回调里用户上传图片后立刻生成 HEIC 副本和 JPEG 缩略图任务队列用现成的消息中间件控制。考虑到目前每张图的转换时间基本都在毫秒级瓶颈反而在磁盘和网络 IO 上。这套方案目前一直在跑没出过乱子。最后再分享一个细节技巧批量转换遇到几百张手机原图时不要一上来就转 HEIC建议先用magick identify -format %f %wx%h %b *.jpg看一下图片尺寸和体积分布。如果里头混着几千像素的大图先统一缩放到合理尺寸再转 HEIC体积和速度都会换来不小提升。磨刀不误砍柴工这个习惯能帮你避免很多不必要的 CPU 和存储开销。
返回列表