Favicon 生成
一张方图或两个字母生成 ico/png,并给出 head 片段。
这一页把一张方图或两个字母摊成一整套站点图标:按尺寸档导出多张 PNG、自己拼一个 ICO 容器、再给出可粘进 <head> 的 link 片段和一份 site.webmanifest 文本。图片只从文件选择、拖放或粘贴进入,解码、重绘、编码全部在浏览器内存里完成;字母档不下载任何字体,只用本机通用字族。ICO 容器是本页按字节拼出来的,不依赖任何图标库;容器生成完会立刻用 parseIco 把自家产物再读一遍,页面上那张结构表和「回读自洽」的结论来自这次回读,而不是写入时的乐观假设。
本页代码里没有 fetch、XHR 与 sendBeacon,也故意不提供「从 URL 载入图片」的输入框——那等于替你把一次图片请求发到站外,和整站不上传内容的口径相反。大于 256 的尺寸根本进不了 ICO,只能出 PNG。每档那个「疑似发糊」的判定只是与理想降采样的偏差比较,套了 maskable 安全区、或目标不小于工作底稿的档不参与判定,并把不参与的原因写在同一行。本页不为 maskable 另出一份文件,安全区是直接套在那档导出的 PNG 上,所以那张图在未被遮罩的场景里也是缩过一圈的。「下载全部」是逐个触发 <a download>,N 个独立文件、不是压缩包(本项目不引入 JSZip);片段和 manifest 都是普通可选中文本,自行选中复制,这两块没有复制按钮。
Favicon 生成怎么用
- 选来源:图片模式接 PNG/JPEG/WebP/GIF/SVG;字母模式取前两个词的首字母并转大写、中文取前两个字,底色由文字哈希定色相、饱和度 62%、亮度 46%,字色在白与近黑之间按 WCAG 对比度取更高的那个,页面同时给出对比度数值和是否过正文 4.5:1 这条线(你手填了合法底色就以你为准,只重选字色)。外形三档:圆、圆角方(半径 22% 边长)、直角方。SVG 载入时先做体检,外部 image/font 引用、script、foreignObject、有没有 width/height 与 viewBox 都会列出来——前几项会让栅格化出来的画布是空白的。
- 定尺寸与处理:预设四档或直接勾尺寸;fit 三选一决定非方图怎么变方;maskable 开关默认打开,只作用于大于等于 192 的档,内缩比例可调。生成后最上面是最大一档的 1:1 主预览,下面每档一行:缩略(64px 及以下的档给 1:1 真实尺寸那颗,更大的档写「1:1 见主预览」,并一律再配一张放大到 64px 显示成品——倍率按 max(2, round(96 ÷ 档位)) 随档位变,悬停标题写明几倍,判清晰度看这张)、尺寸(>256 标「仅 PNG」、套了安全区标 maskable、比底稿大标放大档、180 那档另存苹果默认名)、格式、字节数、判定与说明(疑似发糊/偏差可接受/未判定,后跟不参与判定的原因,再加有墨与中间调两个占比),最末一列是这一档的下载按钮。ICO 单独一行,条目数与「回读自洽 / 回读发现 N 处问题」写在这几列里,目录头与每条 16 字节的明细在下面那张结构表。
- 取文件与粘片段:每个尺寸一张 PNG,外加一个 ICO(条目就是所有小于等于 256 的档,编码档可选 PNG 内嵌、BMP + AND 掩码或混合),单张下载或全部下载都行:「下载全部」是逐个触发 <a download>,N 个独立文件、不是压缩包(本项目不引入 JSZip),浏览器会询问是否允许下载多个文件;head 片段与 site.webmanifest 是文本,按你自己的构建流程落盘——本页不写文件、不发起请求,也替不了你把它们部署到服务器上。
- ICO 容器的字节布局:6 字节 ICONDIR 依次写 idReserved=0、idType=1、idCount(三个都是小端 16 位),其后每条 16 字节 ICONDIRENTRY 依序是 bWidth、bHeight、bColorCount、bReserved、wPlanes、wBitCount、dwBytesInRes、dwImageOffset,偏移量按「目录头 + 前序条目长度」累加,所以条目首尾相接正好铺满整个文件。bWidth/bHeight 只有 1 字节,256 必须写成 0、读回来时 0 也按 256 解释。回读自检里,偏移不连续、类型不是 1、尾部多余字节、条目不是从小到大都会被点名。
- 尺寸档与降采样:尺寸档是四组预设:最小可用 16/32、标准桌面 16/32/48(默认)、桌面 + PWA 16/32/48/192/512、全家桶 16/32/48/64/180/192/256/512,也可以自己勾。选择逻辑先去重、再按从小到大排序——ICO 条目顺序影响老路径的挑选,而「从小到大」是这一步的责任,不是容器的魔法;非正整数单独报原因,大于 256 的档只出 PNG 不进 ICO 并写明为什么。源图比某个请求尺寸还小时那一档照样产出,但会打上放大档标记,提示条按实际档数报数量(1 档就说 1 档,不写死数字)。降采样不是一步 drawImage,而是每次折半、imageSmoothingQuality 设为 high 逐级降到目标尺寸。每档还做一次「与理想降采样比」的体检:把原图按整数面积平均直接盒滤波成目标尺寸的灰度图,与浏览器降采样结果比平均绝对差和梯度能量比,偏差过大标「疑似发糊」。
常见问题
浏览器不是会自动请求根目录的 /favicon.ico 吗,为什么还要写这些 link?
自动请求这个回退行为确实有文档记录(文件不存在时还会在访问日志里留下一堆 404),但「已经声明了 link 还要不要发这次请求」各浏览器并不一致,所以本页只建议根目录放一份当保险,不把它当可靠机制。真正决定用哪张图的是片段里这些 link,浏览器按书写顺序挑第一个它能用且尺寸匹配的;这也是为什么 ICO 那行把 sizes 列全,PNG 那行一档一条。
ICO 里的图是 PNG 还是 BMP,选错了会怎样?
三个编码档都在:PNG 内嵌(默认,体积小)、BMP 档(32bpp DIB 加 1bpp AND 掩码,biHeight 写成 2 倍高、像素自下而上)、混合(48 及以下用 DIB,更大用 PNG)。要留意的兼容事实是:ICO 内嵌 PNG 是 Windows Vista 才加入的支持,MDN 的图像格式指南因此建议 ICO 里用 BMP,并说明 PNG 内嵌可能得不到良好支持——照顾老 IE 或老资源管理器就切到 bmp 或 mixed。代价在另一头:AND 掩码是 1bpp 的,阈值默认 255,alpha 不等于 255 的像素一律被记成透明,也就是说只有「全透明/全不透明」两档,半透明羽化边缘会变硬。这就是同一份图标里 PNG 条目存在的理由,也是混合档把小尺寸留给 DIB 的理由。
16px 那档看着就是一团糊,是工具算错了吗?
不是,是三件事叠出来的。源图非方时留白档在 16px 上只剩十来个像素高;请求尺寸比源图大时那一档是插值放大出来的,页面已经把它标成放大档并说明「别指望它变清晰」;浏览器一步 drawImage 的降采样也不等于面积平均,本页就把两者之差量化成平均绝对差与能量比,超阈值的标「疑似发糊」。能改的只有源头:给一张正方、边长不小于最大请求档、细节不要太密的图,或者把明显放大的那一档从勾选里去掉。
非方的源图是怎么变方的?
非方源图先按你选的 fit 落到方画布:等比留白(letterbox,四周补透明边,小尺寸时有效像素变少、最容易糊)、等比裁切(填满方形、长边方向被切掉)、非等比拉伸(填满但变形,圆变椭圆)。三档用的是同一条 fitRect 算式,1000×400 的源进 32×32 的画布时,留白档的内容只有 32×12.8、上下各补 9.6px,裁切档取的是源图横向 300–700px 那一段。
head 片段和 manifest 里到底写了什么?
代码输出只有两块,都是纯文本。head 片段第一行是说明注释,随后是带 sizes="16x16 32x32 48x48"(只列得出得来的小于等于 256 的档)的 image/vnd.microsoft.icon 一行,可选的老 IE rel="shortcut icon"(注释里写着现代浏览器会忽略它),可选的 SVG 两行(rel="icon" type="image/svg+xml" 与 rel="mask-icon",注释注明 SVG 只在部分浏览器作 rel=icon 生效,别只靠它),接着每个 PNG 尺寸一行 <link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">,再来一行 rel="apple-touch-icon" sizes="180x180"、一行 rel="manifest"、一行 <meta name="theme-color">;属性值统一走转义,路径里出现的空格、引号、尖括号都会被实体化,命名模板与路径前缀另有空格/非 ASCII/大小写三类风险提醒。下载的 PNG 文件名跟着你的命名模板(默认 favicon-{w}x{w}.png);勾了 180 这一档时,除模板名外再按苹果默认名存一份字节相同的 apple-touch-icon.png,head 片段里那行指的就是它,没勾 180 则片段里根本不出现 apple-touch-icon 行。manifest 的 icons 里每个 PNG 档都有一条 purpose 为 any,勾了 maskable 时大于等于 192 的档再补一条 purpose 为 maskable,两条用的是同一个 src(安全区的内容按内缩百分比缩小、四周铺上底色,默认 10%)。片段和 manifest 各自待在一个折叠块里(块头的计数:前者写片段的行数,后者写 manifest 的 icons 条数——按 any 与 maskable 分开数——和这段 JSON 的字节数);收起折叠不影响已经生成的文件与下载按钮。
对应功能编号 #80无需安装,手机端同样可用按 Ctrl + K 换工具