1. ICNS 简介
ICNS是macOS中使用的一种图标格式。它支持16*16,32*32,48*48,128*128,256*256,512*512像素的图标。比例为1x和2x,具有1位和8位alpha通道和多种图像状态
2. ICNS 文件结构
ICNS文件格式由一个 8 字节的头部和任意数量的图标组成。
2.1 头部数据说明
| 偏移量 | 尺寸 | 说明 |
|---|---|---|
| 0 | 4 | 文件类型标识, 要求一定是"icns" |
| 4 | 4 | 文件长度, 以字节为单位 |
const icns = fs.readFileSync("./test.icns")
const type = icns.toString("ascii", 0, 4) // "icns"
const size = icns.readUInt32BE(4) //992082
2.2 图标数据说明
图标数据需要注意的是:
ICNS数据除去头部8位, 剩下的就是图标集数据。图标集数据是由多个图标数据拼接而成。
我们该如何对这条数据进行切割呢? 每一个图标数据都包含三个部分, 0-4位表示图标类型, 4-8位表示数据长度,即这条图标数据在哪里结束, 如4-8位值为1000, 那么图标数据是8-1008
| 偏移量 | 尺寸 | 说明 |
|---|---|---|
| 0 | 4 | 图标类型 |
| 4 | 4 | 数据长度 |
| 8 | 数据长度 | 图标数据 |
const icns = fs.readFileSync("./test.icns")
const chunk = icns.slice(8) //需要除去头部数据
const type = chunk.toString("ascii", 0, 4)
const size = chunk.readUInt32BE(4) //992082
const data = chunk.slice(8, size)
3. 代码实现
const fs = require('fs');
const icns = fs.readFileSync('./test.icns');
const type = icns.toString("ascii,0,4") // 'icns'
const bytes = icns.readUInt32BE(4);
let buffer = icns.slice(8);
const result = [];
while (buffer.length > 0) {
const size = buffer.readUInt32BE(4);
const image = buffer.slice(8, size);
buffer = buffer.slice(size);
const imageHeader = image.slice(0, 8).toString('hex');
//根据PNG文件的定义来说,其文件头位置总是由位固定的字节来描述的:
//十六进制数: 89 50 4E 47 0D 0A 1A 0A
if (imageHeader === '89504e470d0a1a0a'){
result.push(image)
};
}
result.forEach((image, index) => {
fs.writeFileSync(`./${index}.png`, image);
});