手绘示意图:一个 ICNS 文件在 Mac 桌面上被拆解成不同尺寸的 PNG 切片,旁边的压缩仪表盘显示体积缩减
ICNS macOS 图片压缩 应用图标 Zipic

Mac 上压缩 ICNS 文件:拆解格式内部结构与逐切片优化

2026-05-09 Zipic Team

在 Mac 上压缩 ICNS 文件——拆解 ICNS 容器内的 PNG 切片结构,了解为什么 iconutil 不够用,以及 Zipic 如何用自研 pngoptim 引擎逐片优化应用图标。

每个 macOS 应用的 .app 包里都藏着一个 .icns 文件。Finder 在 Dock、Spotlight、文件选择器里画出的那个图标,就是从这个文件读的。大多数开发者在 Xcode 生成完就再也不碰它——问题就出在这里。

第三方应用的 .icns 文件通常在 500 KB 到 1 MB 以上,因为 iconutil 只是把源 PNG 原封不动地塞进容器,不做任何压缩。Apple 自家系统应用用 JPEG 2000 编码内部切片,所以能控制在 65 KB 以内;但第三方工具链默认输出 PNG,压缩率为零。其中 1024×1024 的 Retina 切片一片就能占掉全部体积的 60–85%。这份臃肿会渗透到 .app 包、DMG 安装盘,以及——如果你用 Sparkle——每次发给用户的增量更新补丁里。

这篇文章把 ICNS 格式拆开看,解释为什么 iconutilImage2Icon 都无法缩减体积,再走一遍 Zipic 如何用自研的 pngoptim Rust 引擎对 ICNS 做逐 PNG 切片压缩。本文是 pngoptim 引擎系列的第二篇——第一篇讲了 APNG 压缩pngoptim 深入解析 讲引擎内部架构。

ICNS 文件里到底装了什么

ICNS 不是一张图——它是一个 容器。可以把它理解成一个扁平归档:每个条目存储一个特定像素尺寸的图标。文件以 8 字节头部开头:4 字节魔术字 icns 加上 4 字节大端序的文件总长。此后每个元素由 4 字节 OSType 编码 + 4 字节长度 + 原始图像数据组成。

一个由 iconutil 构建的现代 .icns 最多包含 10 个 PNG 切片:

槽位像素尺寸OSType用途
16×1616×16icp4Finder 列表视图、菜单栏
16×16@2x32×32ic11Retina 列表视图
32×3232×32icp5Finder 分栏视图
32×32@2x64×64ic12Retina 分栏视图
128×128128×128ic07Finder 图标视图
128×128@2x256×256ic13Retina 图标视图
256×256256×256ic08大图标视图
256×256@2x512×512ic14Retina 大图标视图
512×512512×512ic09全尺寸预览
512×512@2x1024×1024ic10Retina 全尺寸 / App Store

注意 ic10:它实际存储 1024×1024 像素,但代表 512×512 (@2x 密度)。这就是为什么 .iconset 文件夹里会出现 [email protected] 这个名字——文件本身其实是 1024 像素的正方形。

Retina 之前的旧 ICNS 还会携带历史遗留 chunk——1-bit 掩码(ICN#ics#)、4/8-bit 索引色(icl4ics8)、PackBits RLE 压缩的 24-bit RGB(il32 + l8mk)。现代 macOS 渲染时不读这些数据,它们只为兼容 Mac OS 9 和早期 OS X 而保留。如果源 .icns 仍然带着这些历史包袱,Zipic 在重新打包时会清除掉。

这个格式没有 Apple 发布的独立规范。最完整的公开参考是 Wikipedia 的 Apple Icon Image format 条目;Apple 在其 High Resolution Guidelinesiconutil man page 中记录了 .iconset 工作流。

ICNS 出现在哪里,体积为什么重要

ICNS 遍布 macOS:

  • 应用包 —— MyApp.app/Contents/Resources/AppIcon.icns,由 Info.plistCFBundleIconFile 键指向。这是最核心的用途。
  • 磁盘映像 —— DMG 的自定义卷标图标存储为根目录的 .VolumeIcon.icns。如果 DMG 图标是 900 KB 而应用本身才 15 MB,安装包仅因一个装饰性文件就多了 6% 的体积。
  • 文档类型图标 —— 应用通过 CFBundleDocumentTypes 注册自定义文档图标。一套丰富的文档图标可以额外增加数百 KB。
  • 系统图标 —— macOS 在 /System/Library/CoreServices/CoreTypes.bundle/ 里存储了数百个 ICNS,对应文件夹类型、磁盘类型和文件关联。

体积直接影响三件事:

  1. 包体积。 App Store 审核人员和用户都会注意下载体积。20 MB 的应用里一个 1 MB 的 ICNS 就是 5%——只为了一个装饰性文件。
  2. Sparkle 增量更新。 Sparkle 的 增量更新系统bsdiff 逐文件生成二进制差分。PNG 数据结构噪声大——像素微调就会产生大量差异。臃肿的 ICNS 一旦在版本间变动,就可能主导整个补丁包的大小。Sparkle 官方文档明确提醒:“Do not make unnecessary modifications to files.”
  3. DMG 下载时间。 自定义卷标图标影响每个下载安装器的用户。60 KB 对比 900 KB 的 ICNS 每次下载节省 840 KB——10 万次下载就超过 80 GB 带宽。

为什么只用 iconutil 不够

Apple 的 iconutil 做两件事:把 .iconset 文件夹转成 .icnsiconutil -c icns)和把 .icns 拆回 .iconseticonutil -c iconset)。功能到此为止。

iconutil 做不到 的事:

  • 不优化 PNG。 你给它什么 PNG,它就原样包进 ICNS chunk 头。如果源 PNG 是 Figma、Sketch 或截图的未优化导出,iconutil 会原封不动地打包。
  • 不缩放尺寸。 每个 PNG 必须已经是上表中要求的精确像素尺寸。
  • 不清除元数据。 源 PNG 里的 EXIF、ICC 配置文件和文本 chunk 会一路带进 ICNS。
  • 不从单张源图生成全套图标。 你得自己准备好全部 10 个尺寸。

这就是为什么第三方应用的 iconutil 生成的 ICNS 比 Apple 系统图标大得多:Apple 系统图标内部用 JPEG 2000 编码,而 iconutil 只输出 PNG。

Image2Icon(img2icnsapp.com)填的是另一个空缺——它能从一张源图自动生成全部 10 个尺寸变体,支持模板和多种导出格式。但它关心的是 生成,不是 压缩。它不会对生成的 PNG 切片做有损量化。

空缺很明显:整条流水线上没有任何环节会在 PNG 打包进 ICNS 之前做优化。Zipic 补的就是这个缺。

Zipic 怎么压缩 ICNS 文件

Zipic 把 ICNS 当作三阶段流水线来处理:

  1. 拆包。 调用 iconutil -c iconset 把源 .icns 的每个 PNG 切片提取到临时 .iconset 文件夹。
  2. 逐切片压缩。 每个提取出来的 PNG 都经过 Zipic 自研的 pngoptim 引擎——就是 Zipic Pro 里驱动 APNG 压缩 的同一个 Rust 量化器。pngoptim 执行有损调色板量化(中值切割 + Floyd–Steinberg 抖动)、清除元数据、优化 deflate 流。平均速度比 pngquant 快 1.69 倍,相同质量下文件再小 2–3%
  3. 重新打包。 对优化后的 .iconset 调用 iconutil -c icns,重新组装 ICNS 容器。

结果:每个切片都被单独优化,容器结构合法,macOS 渲染出来的图标和以前一模一样——只是文件更小了。

Zipic 主窗口显示 ICNS 文件经过切片级压缩后的体积缩减百分比

配置 ICNS 压缩预设

ICNS 压缩属于 Zipic Pro 功能。点击主窗口左下角的 压缩设置

Zipic 压缩设置面板,用于配置 ICNS 图标优化参数
设置推荐值原因
压缩等级2–3图标多为扁平配色加硬边缘,2–3 级在保留细节的同时能减掉 40–80% 的 PNG 重量
保存格式保持原格式ICNS 内部必须是 PNG,没有”把 ICNS 转成 WebP”这回事
尺寸调整关闭绝对不要改变图标尺寸——.iconset 约定要求精确到像素
保存位置覆盖原文件或输出到同级文件夹自动化构建用覆盖;手动 A/B 对比用同级文件夹

.icns 文件(或者直接把应用包的 Contents/Resources/ 文件夹)拖进主窗口。Zipic 检测到 ICNS 格式后自动拆包、用 pngoptim 逐切片压缩、再重新打包。点击缩略图打开对比预览,确认每个尺寸下图标依然锐利。

实测:1 MB ICNS → 不到 200 KB

Electron 应用是重灾区。Claude 桌面版的 electron.icns1,084 KB,包含 6 个未优化的 PNG 切片。其中最大的 [email protected](1024×1024 像素)单片就有 735 KB。

经过 Zipic 处理后:

切片压缩前压缩后缩减
512×512@2x(1024 px)735 KB~102 KB86%
512×512246 KB~34 KB86%
256×25677 KB~12 KB84%
128×12822 KB~4 KB80%
32×322.2 KB~0.8 KB62%
16×160.8 KB~0.6 KB32%

PNG 切片合计从 1,083 KB 降到约 155 KB——原始图像数据缩减 85%。重新打包后的 ICNS 大约 150–200 KB,具体取决于 iconutil 在拆包/重新打包过程中重建了多少遗留 chunk。即使是 50–100 KB 范围内已经比较合理的原生 macOS 应用图标,通常也能再省 20–40%,因为设计师从 Figma 等工具导出 PNG 时不会跑量化器。

把 ICNS 压缩集成到构建流程

Xcode Build Phase

在 Copy Resources 步骤之后加一个 Run Script 构建阶段:

ICNS_PATH="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Resources/AppIcon.icns"
if [ -f "$ICNS_PATH" ]; then
  open "zipic://compress?url=${ICNS_PATH}&format=original&level=3&location=original"
fi

这通过 Zipic 的 URL Scheme 触发就地压缩。Zipic 异步运行,不阻塞构建。

文件夹监控用于 CI 资源

如果你的 CI 把图标导出到共享文件夹,可以用 Zipic 的 文件夹监控 盯住那个目录。每个新 .icns 文件都会自动触发压缩,使用你保存的预设,无需手动干预。

Sparkle 增量更新优化

如果你通过 Sparkle 分发更新,在签名更新包之前压缩 ICNS 意味着:

  • 更小的基础归档(.zip.dmg
  • 更小的增量补丁——因为优化后的 PNG 结构噪声更低,bsdiff 的差分更紧凑
  • 图标没有变动的版本之间 ICNS 字节保持一致(未优化的 PNG 即使源稿相同,每次导出结果也可能不同)

ICNS 与其他图标格式对比

格式平台尺寸范围压缩方式Retina 支持工具
ICNSmacOS16–1024 px,含 @2x每切片 PNG 或 JPEG 2000支持iconutil、Zipic
ICOWindows16–256 px每槽 BMP 或 PNG有限各类编辑器
Asset Catalog(.car)iOS / macOS(现代)按槽位 PNG/PDFactool 重打包支持Xcode
Adaptive IconAndroid108×108 dp前景/背景分层通过密度分桶Android Studio
FaviconWeb16–512 pxICO、PNG 或 SVG通过 manifest任意图片工具

ICNS 是唯一一个你能打开容器、逐切片独立优化、再重新打包的格式——Zipic 正是利用了这个特性。

FAQ

Zipic 会改变 ICNS 的容器结构吗? 不会。Zipic 用 Apple 自己的 iconutil 做拆包和重新打包,所以输出的 .icns 在结构上和 Xcode 生成的完全一致——只是内部的 PNG 更小。

压缩后图标在 Dock 或 Finder 里看起来会不一样吗? 压缩等级 2–3 时,在图标显示尺寸下差异不可见。有损 PNG 压缩引入的量化痕迹在 128×128 及以下分辨率是亚像素级的。用 Zipic 的对比预览确认后再提交即可。

能压缩不是自己构建的应用的 .icns 吗? 可以。把任意 .icns 拖进 Zipic 就行。这对精简 DMG 卷标图标或自定义文件夹图标很实用。但要注意:修改已签名应用包里的图标会让代码签名失效——只对你自己控制的包做压缩,然后重新签名。

为什么 ICNS 压缩是 Pro 功能? ICNS 压缩依赖 pngoptim 引擎,它与 zipic-jpeg、gifoptim、svgo-swift、pdfoptim 一样,属于 Pro 订阅资助的格式专属引擎。免费版覆盖常规图片压缩面。

Zipic 能处理遗留 ICNS chunk(RLE、JPEG 2000)吗? Zipic 只对现代 ICNS 文件内的 PNG 切片做优化。遗留 chunk(PackBits RLE、1-bit 掩码、JPEG 2000)在拆包/重新打包过程中会被保留但不单独优化——现代 macOS 渲染时也不使用这些数据。

和手动对 iconset 跑 pngquant 比呢? 思路一样,步骤更少。你 可以 自己跑 iconutil -c iconsetpngquant *.pngiconutil -c icns。Zipic 用 pngoptim(速度更快、体积更小)把这条流水线自动化成一次拖放操作,还帮你处理了临时目录清理和 .iconset 文件命名约定。

引用来源

相关文章

试试 Zipic

应用图标是用户最先看到的东西,却是开发者最后才想起优化的对象。下载 Zipic,设一个等级 3 的预设,把 .icns 拖进去。pngoptim 引擎负责逐切片压缩,iconutil 负责重新打包。ICNS 压缩是 Pro 功能——下载即享 7 天完整 Pro 体验。查看 定价

相关阅读