Skip to content
Go back
Table of Contents

將Windows動態光標主題移植到Linux下

前言

前段時間在B站發現了一個很可愛的鼠標主題, 出處在這裡, 解壓之後自然發現只能在Windows下使用, 雖然已經在Windows下更換使用了一段時間, 但是覺得沒能在自己的Linux主力機上使用還是有點可惜, 於是打算自己進行移植.

1. 直接轉換

我在深度論壇上發現了這樣一篇文章, 並照着它的步驟進行了移植, 這篇文章寫得很好, 整個過程都相當正常的走完, 成功的將.ani文件移植成X11光標文件. 可當我正打算使用的時候卻發現有一點不對勁.

不正常光標

相比之下, 正常的KDE桌面X11光標大小都在12px-72px之間, 而這個光標主題大小居然高達160px, 大的根本沒法用.

2. 使用Greenfish Icon Editor Pro進行編輯之後安裝

我在嘗試使用GIMP和RealWorld Cursor Editor編輯光標文件後均以失敗告終, 因為GIMP在修改圖像大小時會改變圖像性質, 不能保存為X11光標, RealWorld Cursor Editor改變光標大小的步驟十分繁瑣, 對於單個光標文件需要逐個修改7-8幀的動態光標來說這個工作量已經不太可能一個人完成.

最後我找到了一個更好的圖像編輯器, 能夠相對更方便的編輯光標文件, 並且可以雙向轉換Windows和Linux的光標主題文件

安裝方式:deb下載地址, Arch可以直接在Aur找到, 包名為 gfie-bin.

2.1 修改大小

安裝完成後打開一個ani文件, 右鍵點擊頁, 選擇頁屬性

選擇頁屬性

在其中自定義大小之後點確定保存

自定義大小

另存為X11光標文件

另存為

2.2 創建鏈接映射

Windows動態光標只有很少的文件數量, 但是一個X11光標主題卻包含大量不同名字的光標文件, 其中大部分是鏈接文件. 此時需要對照一個主題對原有的文件進行逐一鏈接. 我對照的是默認的breeze主題, 並事先給原有的光標文件改了名字.

重命名後的原始文件

此時建立一個這樣的目錄

.
├── cursors/
├── index.theme(主題引導文件)
├── *make(鏈接腳本文件)
└── origin/
    └── 原始的光標文件

按照系統中已有的主題編寫鏈接腳本, 以下是鏈接腳本的一部分, 完整的鏈接腳本可以在項目的github主頁獲取

#! /usr/bin/bash

#copy orgin files to cursors dir
cp ./origin/* ./cursors/

#make hard links
ln  ./cursors/waiting              ./cursors/00000000000000020006000e7e9ffc3f    # progress
ln  ./cursors/vertical_resize      ./cursors/00008160000006810000408080010102    # size_ver
ln  ./cursors/forbidden            ./cursors/03b6e0fcb3499374a867c041f52298f0    # circle
ln  ./cursors/waiting              ./cursors/08e8e1c95fe2fc01f976f1e063a24ccd    # progress
ln  ./cursors/normal               ./cursors/1081e37283d90000800003c07f3ef6bf    # copy
ln  ./cursors/link                 ./cursors/3085a0e285430894940527032f8b26df    # alias
ln  ./cursors/waiting              ./cursors/3ecb610c1bf2410f44200f48c40d3599    # progress
ln  ./cursors/normal               ./cursors/4498f0e0c1937ffe01fd06f973665830    # dnd-move
ln  ./cursors/person_select        ./cursors/5c6cd98b3f3ebcb1f9c7f1c204630408    # help
ln  ./cursors/normal               ./cursors/6407b0e94181790501fd1e167b474872    # copy
ln  ./cursors/link                 ./cursors/640fb0e74195791501fd1ed57b41487f    # alias
ln  ./cursors/normal               ./cursors/9081237383d90e509aa00f00170e968f    # dnd-move
ln  ./cursors/link                 ./cursors/9d800788f1b08800ae810202380a0822    # pointer
ln  ./cursors/link                 ./cursors/a2a266d0498c3104214a47bd64ab0fc8    # alias
ln  ./cursors/link                 ./cursors/alias
ln  ./cursors/move                 ./cursors/all-scroll
ln  ./cursors/normal               ./cursors/arrow                               # default
ln  ./cursors/normal               ./cursors/b66166c04f8c3109214a4fbd64a50fc8    # copy
ln  ./cursors/diagonal_resize2     ./cursors/bottom_left_corner
ln  ./cursors/diagonal_resize1     ./cursors/bottom_right_corner
ln  ./cursors/vertical_resize      ./cursors/bottom_side
ln  ./cursors/move                 ./cursors/cell
ln  ./cursors/point_hand           ./cursors/center_ptr
ln  ./cursors/forbidden            ./cursors/circle                              # not-allowed
ln  ./cursors/normal               ./cursors/closedhand                          # dnd-move
ln  ./cursors/handwriting          ./cursors/color-picker
ln  ./cursors/horizonal_resize     ./cursors/col-resize
ln  ./cursors/normal               ./cursors/context-menu
ln  ./cursors/normal               ./cursors/copy

運行腳本就能在cursors目錄中創建完整的主題文件, 此時將這個文件夾放在/usr/share/icons/下, 就能在KDE設置中看到光標主題.


二編

我的確沒想到會有人來請求做另一版本的光標. 並且過了一年, 開始使用 Niri 作為視窗管理器之後由於老版本光標沒法調整大小, 已經 棄用一段時間. 既然有人請求, 那我就恰好做下一版.

設計思路

一年前, 我是直接手工的轉換尺寸, 並手動編寫腳本來做映射. 這樣的成本在今天看來是難以接受的, 我不再有閒功夫來一個個去做轉換. 因此, 這一次我要尋求足夠自動化的解決方案. 這個任務可以被分成多個階段完成, 很適合使用流水線 (pipeline) 的方式實現. 我們 可以這樣描述一個 foo.ani 的處理流程:

  • Extract

    foo.ani 文件裡面有多個幀的圖片數據, 以及記錄了熱點信息和時間信息. 然而生成 xcursor 的程序 xcursorgen 非常簡陋, 只能讀取 png 文件和事先寫好的配置文件, 因此需要進行解包. 將裡面的文件和數據分離, 並讀取信息.

    Note

    熱點信息是光標的聚焦點座標, 也就是計算點擊事件的接觸點在整個貼圖上的位置.

  • Resize

    我們需要生成多種尺寸的光標, 就需要對光標進行 resize, 同時這一步還需要把解包出的各幀 ico 圖像轉換成 png 格式.

  • GenIn

    現在所有材料已經準備完畢, 需要根據解包出的信息生成 xcursor.in.

  • GenXcur

    調用 xcursorgen 程序, 根據解包出的圖片和生成的配置文件生成光標文件.

  • Alias

    這是整個流水線的最後一步, 由於 xcursor 和 windows 的光標並不是一一對應, 所以需要一個映射方案. 好消息是所有 x 光標 都能被映射到 windows 光標的一個形態. 壞消息是我不知道映射規則, 這只能靠看著形態硬排. 我為了方便修改, 寫了一個 json 格式的配置, 用來方便的儲存映射表.

    {
      "help": [
        "help"
      ],
      "work": [
        "3ecb610c1bf2410f44200f48c40d3599",
        "08e8e1c95fe2fc01f976f1e063a24ccd",
        "00000000000000020006000e7e9ffc3f",
        "half-busy",
        "left_ptr_watch",
        "progress",
        "waiting"
      ],
      "busy": [
        "busy",
        "wait",
        "watch"
      ],
      "cross": [
        "cross",
        "crosshair",
        "tcross",
        "not-allowed"
      ],
      "text": [
        "ibeam",
        "text",
        "xterm"
      ],
      "handwrt": [
        "color-picker",
        "draft",
        "handwriting",
        "pencil"
      ],
      ...
    }

    這樣在修改映射方案的時候不必頻繁的修改代碼, 也可以寫多套映射表.

實現方案

我在第一步就卡住了, 因為目前並沒有庫能夠解析 windows 的 ani 格式文件. Python 的 Pillow 只能解析 cur 文件, 且不能獲取熱點信息. 但是我在 arch 論壇上找到了一篇文章 於是我也用 c 寫了一個程序, 來解析 ani 文件, 並且能夠以 json 格式輸出信息. 源碼位於這個倉庫

解包

我使用 python 腳本來驅動整個過程, 源碼位於 Ani2Xcur.

TODO

現在的這一套代碼仍然不足以轉換所有的動態光標包, 因為很多是混雜 ico 文件的. 我現在還不能從 ico 文件中獲取 熱點信息. 而且很多 *.ani 文件在解析過程中會有斷言錯誤.
我為了方便做了很多假設, 比如假設幀數量等於序列的步驟數量, 實際上可能並不相等, 可能複用幀.

歡迎大家對我的代碼做出改進, 使其能夠支持更廣泛的光標轉換.