Mac黑科技软件、网站iOSmac软件收集

Iconista——Mac下最炫酷的主题图标美化工具

2015-05-31  本文已影响11110人  Uri

Preface

是不是早已受够了系统原有的奇丑无比的图标,对于追求完美不放过任何一个细节的我们来说,这个简直不能忍啊。

Launchpad早期图

整个事情的起因就是这么简单,那天晚上我决定不能再这样下去了,于是乎我便迫不及待的打开电脑,兴致冲冲的干了起来。

在MacOSX下替换App图标主要有两种方式:
1.直接替换App包里的图标
右键>显示包内容>Contents>Resources,备份原来的图标,将你的图标按照原来的重命名。

替换icon.icns即可

2.显示简介里替换

这个比上面的要简单,将图标直接拖到简介里原来的图标上就可以了。

上面说的是替换App的icon,但是Finder废纸篓不能用上述方法,需要前往/系统/资源库/CoreServices,找到Dock,然后进入content>resources,替换相对应的findertrashemptytrashfull图片。注意备份哟!

替换finder

如果故事发展到这里就结束了,那个没有下文了,然而事情没这么简单。

Shell Script

话说刚开始试了几个,感觉还不错。这时候你说干脆写个自动脚本算了,一开始我是拒绝的。可是后来一个一个的替换,一想到还有一百多个图标,实在是太TM蛋疼了。。

为什么用shell脚本?因为我不会啊,正好给自己一个理由去学学shell编程。

(最后才发现,原来替换图标是个大坑,用代码更麻烦。。)

有哪些功能:

# Usage
function usage() {
    echo "[*] Usage:"
    echo "[*] $0 [-i | -r | -h | -d [app_name] | -s [theme] | -f [file] [icon]]"
    echo "[*] -i: install the default icon theme"
    echo "[*] -r: restore the origin icon"
    echo "[*] -d: delete/hide the app in Launchpad"
    echo "[*] -s: install the specified theme"
    echo "[*] -f: set icon for file or folder"
    echo "[*] -h: help"
}

由于某些要对系统文件进行操作,所以需要root权限。

if [ $UID -ne 0 ]; then
    echo "[*] Superuser privileges are required to run this script."
    echo "[*] e.g. \"sudo $0\""
    exit 1
fi

if [ ! $1 ]; then
    usage
    exit 1
fi

从上面我们知道有两种方法可以替换图标,其实这两种方法原理不同。下面我们来分别实现:

1.替换App包里的图标

第一种方法最简单,我们只需要替换相应的/Contents/Resources/的App图标即可。先备份原来的icon文件,然后复制新的icon过来。

# setAppIcon [app_path] [iconfile]
function setAppIcon() {
    apath=$1
    ipath=$2

    # Replace the *.app/Contents/Resources/*.icns
    icon=`readPlist "$apath/Contents/Info.plist" "CFBundleIconFile"`
    if [ "${icon##*.}" != "icns" ]; then
        icon="$icon".icns
    fi

    if [ ! -e "$apath/Contents/Resources/$icon.bak" ]; then
        cp "$apath/Contents/Resources/$icon" "$apath/Contents/Resources/$icon.bak"
    fi
    cp "$ipath" "$apath/Contents/Resources/$icon"
    
    touch "$apath/1"
    rm "$apath/1"
}

咦,最后这个奇葩的touch接着rm是干嘛的,老实说当时我手动替换图标后发现半天没有变化,相信大家试过也是这样。

但是有次不经意间多创建了一个文件,奇怪的发现居然变了,估计是缓存的原因吧,我也不知道。。反正就通过这种方式更新App icon使之生效。。

还有一个问题就是,App中icns格式的图标众多,如何找到其中的icon图标?

Plist文件是以.plist为结尾的文件的总称. 众所周知, Plist在Mac OS X系统中起着举足轻重的作用,就如同Windows里面的Registry一样,系统和程序使用Plist文件来存储自己的安装/配置/属性等信息。

由于每个App的icon文件名不是固定的,但是我们可以在App里的Info.plist文件中找到,其中CFBundleIconFile对应的就是icon文件。

icon=`readPlist "$apath/Contents/Info.plist" "CFBundleIconFile"`

然而怎么读取plist格式的文件呢?

cat命令输出文本然后去匹配读取其中的键值对?太麻烦了,这里我们寻找到了一个自带的工具Plutil

Plutil是开发环境提供的一个命令行命令,使用这个命令可以转换Plist文件的格式,而且可以检查Plist文件的语法和完整性。

通过plutil -p [plist file]可以以键值对的格式输出。最后,读取键值的readPlist函数如下:

# readPlist [plist] [key]
function readPlist() {
    plist=$1
    key=$2

    value=`plutil -p "$plist" | grep $key | awk -F '=>' '{print $2}' | sed -e 's/\"//g'`
    echo $value
}

2.显示简介里替换

首先我们要搞清楚当我们把图片拖到简介里的小图标时到底改变了什么。

我们随便打开一个App看看,感觉里面没有什么啊。

Sketch App

现在,看不到什么并不意味着没有什么,在终端里再看看:

居然发现一个隐藏文件Icon?,看名字也知道是干嘛的了,找了半天原来你在这里!

那个?不是真的问号,而是乱码。其实这个文件的名字应该是Icon\r\r指的就是十六进制的0x0D,因为\r不是可打印字符,所以在终端里显示为?。如果在终端里自动补全的话则会显示Icon^M, ^M 就是 \r

ls -lO

hidden说明这是一个隐藏文件,所以我们在Finder里看不到。

当你尝试打开它时

open Icon^M

打不开,什么都木有。

可是,不知注意到没,好奇怪,为啥这个文件的大小是零啊~

The actual icon data is stored in the file's Resource Fork. These days Mac OS doesn't use actual resource forks, so the image is stored in an HFS extended attribute named com.apple.ResourceFork.

在 Mac OS X 下,文件经常会被附加上 OS X 特有的扩展属性 ( extend attributes ),具体表现是用 ls -l 查看时会有 @ 的标记,这个 @ 属性是用户在 Finder 中对文件进行任意操作后就会被附带上

通过@参数查看扩展属性:

ls -l@ Icon^M

果然icon数据存在com.apple.ResourceFork中。

我们还可以把resource fork里面的数据复制出来:

sudo cp Icon^M/..namedfork/rsrc Icondata

从十六进制数据中很清楚的看出这是一个icns格式的icon。

现在我们已经知道替换的东西在哪里了,接下来就是如何替换了。

这里要用到Xcode里面的Developer Tools一些工具,所以前提是你已安装了Xcode及其Developer Tools,具体过程见代码:

# xcodeDevToolsSetIcon [filepath] [iconfile]
function xcodeDevToolsSetIcon() {
    fpath=$1
    ipath=$2
    xcode_devtools="/Applications/Xcode.app/Contents/Developer/Tools/"

    if [ -d $xcode_devtools ]; then
        if [ -d "$fpath" ]; then
            # $fpath is a direstory
            touch "$fpath/Icon\r"
            cp "$ipath" tempIcon.icns
            sips -i tempIcon.icns > /dev/null 2>&1
            derez -only icns tempIcon.icns > tempicns.rsrc
            rez -a tempicns.rsrc -o "$fpath/Icon\r"
            setfile -a C "$fpath"
            rm tempIcon.icns
            rm tempicns.rsrc
            # hide Icon^M file inside folder
            setfile -a V "$fpath/Icon\r"
        elif [ -e "$fpath" ]; then
            # $fpath is a file
            cp "$ipath" tempIcon.icns
            sips -i tempIcon.icns > /dev/null 2>&1
            derez -only icns tempIcon.icns > tempicns.rsrc
            rez -a tempicns.rsrc -o "$fpath"
            setfile -a C "$fpath"
            rm tempIcon.icns
            rm tempicns.rsrc
        else
            echo "$fpath is NOT a file or direstory"
            exit 1
        fi
    else
        echo "[*] Error: this need Xcode Developer/Tools. Please install it first!"
        exit 1
    fi
}

Whst's more

当上面两个重头完成后,剩下还有一些其他的,比如说替换Finder和废纸篓:

    # Change Finder & Trash app icon
    echo "[*] Replace the Finder & Trash icon ..."
    for img in ${imgs[*]}
    do
        if [ ! -e $dock_res/$img.bak ]; then
            mv $dock_res/$img $dock_res/$img.bak
        else
            rm $dock_res/$img 2> /dev/null
        fi
    done

    for file in $default_theme/Docker/*
    do
        cp -p $file $dock_res/
    done
    # delete caches & restart docker
    find /private/var/ -name *dock.iconcache* -exec rm {} \;
    killall Dock

注意的是,要使Dock的上的图标生效需重启Dock。

隐藏 Launchpad 里的图标:

# hideAppIconInLaunchpad [app_name]
function hideAppIconInLaunchpad() {
    appname=$1
    sqlite3 $(find /private/var/folders -name com.apple.dock.launchpad)/db/db "DELETE FROM apps WHERE title='$appname';"
    killall Dock
}

将动态屏保设置成背景(这是什么鬼。。)

# Make screensaver load as the desktop wallpaper
function screensaverWallpaper() {
    /System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background &
}

当然啦,还要有还原的功能:

# restoreAppIcon [app_path]
function restoreAppIcon() {
    apath=$1

    for bak in "$apath"/Contents/Resources/*.icns.bak
    do
        if [ "$bak" != "$apath/Contents/Resources/*.icns.bak" ]; then
            pre="${bak%.*}"
            rm "$pre"
            cp "$bak" "$pre"
        fi
    done

    if [ -e "$apath/Icon\r" ]; then
        rm "$apath/Icon\r"
    fi

    touch "$apath/1"
    rm "$apath/1"
}
function restoreDocker() {
    for img in ${imgs[*]}
    do
        if [ -e $dock_res/$img.bak ]; then
            mv $dock_res/$img.bak $dock_res/$img
        fi
    done
    find /private/var/ -name *dock.iconcache* -exec rm {} \;
    killall Dock
}

主程序的大部分是逻辑控制,这里就不贴出来了,全部代码请移步Github——Iconista

注:上述所有代码中的 "/Icon\r" 都应该是 "/Icon"$'\r'。为啥会乱码,简书的bug?

Iconista

经过本人的慎重决定,这货的名字就叫Iconista,我们的口号是:不要998,就要Iconista~

本着分享的精神,Iconista是一个开源项目,并且欢迎大家无限次无羞耻的免费使用和反馈。项目地址看这里看这里---->O_O!

使用方法很简单,下载好源码后:

cd build/
sudo ./Iconista -i

即可!
更多的使用方法见文档

这里多说一句的是,默认使用的主题图标来自BlackVariant (Patrick),非商业性免费使用。

其放在/Themes/default/目录下。你也可以使用自己的主题,同时也欢迎大家制作更多更炫酷的主题。

如何自定义主题

/Themes/路径下建立一个以你主题为名字的文件夹,必须包含以下目录:

  • /Applications
  • /Apps
  • /Docker
  • /Utilities

每个文件夹里放相应的icns格式的图标,图标名以App名命名,具体可参考默认主题

这么酷炫的东东怎么能没有主页呢,当然有啦,在这里也预告一下,关于这个页面有好多要讲的,下一篇文章将要带领你体验背后那些不为人知的故事。

地址:http://urinx.github.io/app/iconista/

Iconista主页

Preview

用Mac,自定义主题图标,从此逼格又提升一个数量级。这里我就给大家预览一下最后的效果吧!

这是原先的:


原来的

Iconista后期处理后的:

就是这么任性!

Last

最后的最后,欢迎大家关注我的微信公众号(urinx),满满的干货

如果你有什么建议和想法想和我交流,各种bug想要反馈,或者纯属想要交朋友,这是我的微信(google-2)

wechat

Updates

2015.6.6

  1. 新增了 Mac OS X 10.9 的图标主题
  2. 默认主题补充了更多的第三方App图标
  3. 修复了一些bug

Reference

[0]. MAC系统图标的更换
[1]. 在 10.9 下换 Finder 图标的方法
[2]. plutil(1) Mac OS X Manual Page
[3]. Mac OS X: 编辑PList文件的嵌套键值
[4]. OS X 的一些技巧汇总
[5]. osx - Icon? file on OS X desktop - Super User
[6]. How to change the icon of file in MacOS in Objective-C? - Stack Overflow
[7]. Changing icon of package created by package maker - Stack Overflow
[8]. osx - Manipulate Mac OS X file icons from Automator or command-line - Super User

上一篇 下一篇

猜你喜欢

热点阅读