# 自定义文件扩展名图标的技术原理

2020-10-8, Careone

#### 示例1：自定义 DEB 文件扩展名的图标

1. 在 /usr/share/mime/packages/ 目录下，找到 freedesktop.org.xml 文件。
这个文件里，包含了大量的通用 MIMETYPE 定义数据。
    在这个文件里，搜索 *.deb，可以找到类似这样一段内容
（位置大约在 9896-9959行）：

 ----------------
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">

  <mime-type type="application/vnd.debian.binary-package">
    <comment>Debian package</comment>
    <comment xml:lang="zh_CN">Debian 软件包</comment>
    <comment xml:lang="zh_TW">Debian 軟體包</comment>
    <alias type="application/x-deb"/>
    <alias type="application/x-debian-package"/>
    <generic-icon name="package-x-generic"/>
    <magic priority="50">
      <match value="!&lt;arch&gt;" type="string" offset="0">
        <match value="debian" type="string" offset="8"/>
      </match>
    </magic>
    <glob pattern="*.deb"/>
    <glob pattern="*.udeb"/>
  </mime-type>

</mime-info>
 ----------------

把 <mime-type> 和 </mime-type> 中间的数据，复制并另存为同目录下的另一个
文件，如 001.xml, 并在文件开头、尾部加上相应的格式标签。如：

* 文件头标签：
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">

* 文件尾标签：
</mime-info>

然后，保存文件 001.xml。完整的文件目录位置应该是这样的：
 /usr/share/mime/packages/001.xml

最后，再以 root 用户，或者 sudo 运行命令

sudo update-mime-database /usr/share/mime

即可更新 MIMETYPE 数据库。

提示：
    如果没有手动运行 update-mime-database 命令，但是如果后面有安装或删除软件
包的操作，系统通常也会自动更新 MIMETYPE 数据库。

解析如下：

#### 1. MIMETYPE 类型定义

 <mime-type type="application/vnd.debian.binary-package">

这一行，定义了 mimetype 类型为 application/vnd.debian.binary-package

（注：我们可以自定一个新类型，例如：application/package-deb。相同的扩展名，
可以定义为不同的类型，根据 "magic 内容检测" 和不同的 "优先级 priority" 先后
顺序，来实际确认文件真实类型，而不被扩展名蒙蔽和欺骗。 ）

* 例1：同样是 PGN 扩展名，文件实际内容，可能是中国象棋的棋局文件，也可能是
国际象棋的棋局文件。

* 例2：同样是 BAK 扩展名，文件实际内容，可能是备份文件，也可能是早期版本的
WPS 文档备份副本。

#### 2. 文件图标定义

 <generic-icon name="package-x-generic"/>

这一行，定义了图标的文件名。图标的扩展名格式通常选用 PNG 或者 SVG 格式。
默认图标目录位置，一般为

 /usr/share/icons/hicolor/scalable/mimetypes/*.svg

 /usr/share/icons/hicolor/64x64/mimetypes/*.png
 /usr/share/icons/hicolor/48x48/mimetypes/*.png
 /usr/share/icons/hicolor/32x32/mimetypes/*.png
 /usr/share/icons/hicolor/24x24/mimetypes/*.png
 /usr/share/icons/hicolor/22x22/mimetypes/*.png
 /usr/share/icons/hicolor/16x16/mimetypes/*.png

如：/usr/share/icons/hicolor/scalable/mimetypes/package-x-generic.svg

说明：如果系统找不到对应尺寸的图标，则会根据找到的其它尺寸的图标，自动缩放
调整大小 。

另外，如果是其它图标主题，上面目录名的 hicolor, 可能对应其它名称，如

 /usr/share/icons/gnome/scalable/mimetypes/
 /usr/share/icons/oxygen/scalable/mimetypes/
 /usr/share/icons/Faenza/scalable/mimetypes/
 /usr/share/icons/Papirus/scalable/mimetypes/

最后，再以 root 用户，或者 sudo 运行命令

sudo update-icon-caches /usr/share/icons

即可更新 图标 数据库。

提示：
    如果没有手动运行 update-icon-caches 命令，但是如果后面有安装或删除软件
包的操作，系统通常也会自动更新 MIMETYPE 数据库。

#### 3. 扩展名和 MIMETYPE 类型的优先级

 <magic priority="50">

这一行的数字 50, 代表优先级。通常 freedesktop.org.xml 文件的默认优先级数值是
 50 ，（当然，某些扩展名，默认的数值也可能 60 或者其它）。我们自定义的类型
的 DEB ，优先级数值应大于这里的默认值 50。比如，我们自定义为 59
（范围 51-99）。

#### 4. 对应的扩展名

    <glob pattern="*.deb"/>
    <glob pattern="*.udeb"/>

这两行，表示扩展名为 deb 和 udeb 的文件，都按上面的规则定义来识别和判断文件
类型。

#### 5. 其它标签功能

* 1. magic (通过读取文件前面少量内容，来实际确认文件类型。即使文件名不带扩
展名，如文件名为 001 （而不是 001.xml），也可以通过这种方式，来实际确认文件
类型，并以对应的图标来显示区分。

提示：这个特色功能, 非常实用。在 Windows 操作系统上，是无法做到的。

* 2. alias 和 <sub-class-of type=""/>,

alias 可以指定文件类型的别名。即不同的定义（如来自不同厂家的 CAD 图纸文件，
可能定义的 dwg 和 dxf 图纸文件的 MIMETYPE 并不是一样的）。

    好比菜市场买菜，有人说西红杮，也有人叫番茄，实际指的都是同一种东西。

#### 6. 文件打开关联

以 DEB 扩展名为例，通常我们都希望以 gdebi-gtk 程序来打开 DEB 软件包，可以查
看 /usr/share/applications/gdebi.desktop 这个快速启动菜单文件（功能大致相当于
 Windows 操作系统下的快捷方式）。

里面有几项内容是相关的。示例如下：

 ---------
Exec=gdebi-gtk %f
Icon=gnome-mime-application-x-deb
MimeType=application/vnd.debian.binary-package;
 ---------

1. Exec 即默认打开时运行的命令。
小写的 %f 表示可以打开单个文件，大写的 %F 表示可以打开多个文件。另外还有
 %u, %U 等附加选项，这里不多解说。

2. Icon 指定图标。图标的命名规则和搜索目录位置，与前面介绍的原理相同。

提示：如果是 /usr/share/pixmaps/ 目录下有同名的图片（不包含扩展名），如
gnome-mime-application-x-deb.png
gnome-mime-application-x-deb.xpm
gnome-mime-application-x-deb.svg

等等，也可以被程序搜索到。

当然，也可以直接指定完整图标文件位置，如 /usr/share/pixmaps/xxx.png

3. MimeType 类型

后面的数据，对应 /usr/share/mime/packages/ 目录下的 freedesktop.org.xml
（或者其它 xxx.xml 文件）中的 mime-type 相应标签。

注意：
MimeType 最后面一定要有一个英文分号。另外，支持多个 MIMETYPE 类型，示例：
 ---------
MimeType=application/vnd.debian.binary-package;application/package-deb;
 ---------

最后，再以 root 用户，或者 sudo 运行命令

sudo update-desktop-database /usr/share/applications

即可更新 desktop 数据库。

提示：
    如果没有手动运行 update-desktop-database 命令，但是如果后面有安装或删除
软件包的操作，系统通常也会自动更新 "desktop (快捷菜单命令)" 数据库。

## 技术细节 (2023-5-18 补充)

严格按照 freedesktop.org.xml
（完整路径：/usr/share/mime/packages/freedesktop.org.xml）
里的原始 mime 定义，来命名图标文件名。

如 CAD *.dwg 图纸，对应 MIME 类型是 image/vnd.dwg ，那么图片文件名命名规则就是：
image-vnd.dwg.png （或者 svg 图片格式）。

这样，系统会优先在 /usr/share/icons/ 图标目录下，查找叫这个文件名的图标，而忽略 xml 文件里的 generic-icon 定义。
