需要批次大量修圖時, ImageMagick 超好用。 命令列麻瓜/新手/小學生請跟著我做, 勇敢踏出滑鼠選單便利但局促的保護傘, 感受一下 「用電腦」 跟 「被電腦用」 的差別。
我們從
這六張可愛狗狗圖片 出發。 現實生活中, 當你面對
60 張或 600 張圖片時, 今天學的這幾招會更有感覺;
不過在教室裡面, 老師們總是習慣拿小小數量的資料來解說 :-)
我們的目標是要把這六張圖片都變成大小相同的圖片,
並從 exif 後設資料 (meta data) 當中撈字串出來,
把它寫到相片上。請先用 geeqie
檢視相片。
等一下每次產生新圖片時,
geeqie 會自動更新、 可以點新圖片來看, 不必重新執行。
一、 基本練習
- 安裝套件:
apt-get install imagemagick
這裡面包含本文要用到的 identify、 convert、 montage 三個指令。 - 先學一個很簡單的指令, 就是在螢幕上列印而已:
echo hello
- 再學迴圈跟變數:
for x in earth mars venus ; do echo "hello people from $x !" ; done
注意: 單引號跟雙引號大部分時候效果一樣; 但這裡就不一樣。 這裡必須用雙引號, 裡面的變數才會代換。 - identify 指令可以查看圖片解析度:
identify 3.jpg
- convert 指令的 -crop 功能可以剪裁圖片:
convert -crop 960x800+240+0 3.jpg test.jpg
位置及大小的寫法是 「寬度x高度+左緣+上緣」, 原點在左上角。 - convert 指令的 -resize 功能可以改變圖片解析度:
convert -resize 480 3.jpg test.jpg
或convert -resize x400 3.jpg test.jpg
。 第一句指定寬度, 它自動算高度; 第二句指定高度, 它自動算寬度。 我都不會同時指定寬度與高度; 讓 ImageMagick 根據原圖的寬高比例 (aspect ratio) 來自動幫我計算另一個值, 比較簡單。 - 可以把好幾個動作前後串起來, 例如先裁剪、 再縮小一半:
convert -crop 960x800+240+0 -resize 480 3.jpg test.jpg
二、 統一規格
先把相片變成同樣大小。 因為 ImageMagick 有些特效的範圍是用 pixel 數指定的, 如果圖片大小不一的話, 在大圖上, 特效可能很不明顯, 而在小圖上, 效果可能太誇張。
但是統一規格不能直接 resize -- 如剛剛所說,
有些圖片可能會變太胖, 有些變太瘦。
我們先印出所有圖片的解析度:
identify ?.jpg
出現類似這樣:
1.jpg JPEG 448x298 448x298+0+0 8-bit sRGB 101KB 0.010u 0:00.000 2.jpg[1] JPEG 500x375 500x375+0+0 8-bit sRGB 33.6KB 0.000u 0:00.000 3.jpg[2] JPEG 1920x1200 1920x1200+0+0 8-bit sRGB 436KB 0.000u 0:00.000 4.jpg[3] JPEG 400x267 400x267+0+0 8-bit sRGB 14.9KB 0.000u 0:00.010 5.jpg[4] JPEG 1440x900 1440x900+0+0 8-bit sRGB 111KB 0.000u 0:00.000 6.jpg[5] JPEG 736x552 736x552+0+0 8-bit sRGB 82.3KB 0.010u 0:00.009
用
regexp 把圖片名稱、 圖片寬度、 圖片高度印出來:
identify ?.jpg | perl -ne 'print "$1 $2 $3\n"
if /^(.*\.jpg).*? (\d+)x(\d+)/'
再改印檔名跟 aspect ratio: identify ?.jpg | perl -ne
'printf "$1 %0.2f\n",$2/$3 if /^(.*\.jpg).*? (\d+)x(\d+)/'
最後按照 aspect ratio 大小排序: identify ?.jpg | perl -ne
'printf "$1 %0.2f\n",$2/$3 if /^(.*\.jpg).*? (\d+)x(\d+)/' |
sort -n -k 2
得到:
2.jpg 0.99 6.jpg 1.33 1.jpg 1.50 4.jpg 1.50 3.jpg 1.60 5.jpg 1.60
好, 現在知道 2.jpg 最窄高; 3.jpg 跟 5.jpg 最矮胖。 目標是把所有圖片的 aspect ratio 調成 4:3 。 調整 aspect ratio 很難批次處理, 最多只能分成幾大類各類處理。
第一步先把 2.jpg 的上下各砍掉一點:
convert -crop 500x375+0+64 2.jpg test.jpg
如果從 geeqie 裡面看起來 ok, 再 mv test.jpg 2.jpg
。
這件事當然也可以用 gimp 做; 不過我覺得下指令還是比較快一點。
第二步把所有圖片的高度都變成 600:
mkdir ht ; for f in ?.jpg ;
do convert -resize x600 $f ht/$f ; done
再來, 1.jpg 3.jpg 4.jpg 5.jpg 分別要保留中間、 左邊、 左邊、 中間偏右; 另兩張直接拷貝:
cd ht mkdir ../crop convert -crop 800x600+50+0 1.jpg ../crop/1.jpg convert -crop 800x600+0+0 3.jpg ../crop/3.jpg convert -crop 800x600+0+0 4.jpg ../crop/4.jpg convert -crop 800x600+120+0 5.jpg ../crop/5.jpg cp 2.jpg 6.jpg ../crop
三、 貼字
先手動測試在圖片上貼字: convert -font AR-PL-UKai-TW
-pointsize 24 -stroke '#0008' -undercolor '#ffc8' -gravity South
-annotate +0+5 '馬麻什麼時候回來啊?' 1.jpg test.jpg
這麼長的指令當然不是我自己一口氣寫出來的,
而是上網
爬文、 一點一點蓋出來的。 簡單說明:
- -font AR-PL-UKai-TW 指定字型
- -pointsize 24 指定字型大小
- -stroke '#0008'指定文字顏色 (含透明度)
- -undercolor '#ffc8' 指定文字背景顏色 (含透明度)
- -gravity South 指定字串座落於圖片的那一側
- -annotate +0+5 '馬麻什麼時候回來啊?' 要畫上去的字串, 以及位置
字型的部分, 因為要寫中文, 所以不能用預設值, 一定要指定。
根據
這個問答, 可先用 convert -list font
查詢有哪些字型可用。
我在 lubuntu 上面有安裝 fonts-arphic-ukai 跟 fonts-arphic-uming
兩個套件, 所以有 AR-PL-UKai-TW 跟 AR-PL-UMing-TW 可用。
絞盡腦汁想台詞這種工作, 也是要逐張用工人智慧手工打造的。 不過一貼到圖裡面去, 再要還原或修改, 那就更複雜了。 所以較理想的方式是用 digikam 相片整理軟體 或是用 exiftool 命令列工具 把文字存在 jpg 檔裡面的 IPTC/IIF/XMP/EXIF 欄位, 然後再用指令產生如上的貼字指令。 這就是 「保留原始碼好做事」 的概念。
因為那個過程太囉嗦, 所以我已事先將所有文字存入 ?.jpg 當中。
請在最新的 crop/ 子目錄裡面這樣查看: exiftool -p '$Directory/$FileName
$codedcharacterset $Headline | $Subject | $Keywords' ?.jpg
(這些文字資訊從最開始的解壓縮檔裡面就存在, 一路上一直留著,
不會因修圖而消失。) 其中最重要的是 codedcharacterset 欄位 --
如果沒有設成 UTF8, 大部分欄位都不能存中文。
另外還有 Description 欄位等等, 也許更適合儲存較長的文字;
不過我這裡就簡單採用 Subject 欄位好了。
exiftool 的 -p 選項可以直接想寫什麼就寫什麼; 不過更多時候, 我會先用各種蒐集資訊的指令印出一個對照表, 再用 regexp 把對照表轉成想下的指令。 以下在最新的 crop/ 子目錄下執行:
exiftool -p '$FileName $Subject' ?.jpg > list.txt perl -ne 'print qq(convert -font AR-PL-UKai-TW -pointsize 24 -stroke "#0008" -undercolor "#ffc8" -gravity South -annotate +0+5 "$2" $1 ../cap/$1\n) if /(\S+\.jpg)\s+(.*)/' list.txt
原先單句實驗時, 顏色字串外面用單引號, 像這樣:
'#0008'
但是現在 perl -ne '...'
也要用單引號,
所以只好把顏色字串改成雙引號。 那 perl 本身的 print 呢?
還好 perl 可以用 qq(...)
代表雙引號。
如果印出來的指令看來正確, 就先建一個空目錄 mkdir ../cap
然後上箭頭叫出上面那一長句, 最後面再加上
| bash
真的執行下去。
再補一句 montage -tile 2x -geometry 400 ?.jpg dogs-montaged.jpg
合併所有圖片產生本文最上面的成果。 這個 montage 指令也是
ImageMagick 套件的一部分。 上面的指令以每列 2 張的方式合併,
每張小圖寬度 400。
四、 心得及結語
ImageMagick 還有超多特效可用, 請見 官網。 這個網站 拿 IM 組合出很多驚豔的效果, 可惜他們的作品並不是自由軟體。
以下是一些不錯的 IM 中文教學:
在命令列上要批次處理大量的檔案, 通常有兩個方法: 如果只是單純一堆檔名, 可以用 for 迴圈; 如果每個檔名還會搭配不同的參數, 那可能用 regexp 產生命令會比較方便。
下指令就像蓋房子一樣, 第一眼直接看到完整的指令, 可能會覺得很雄偉很可敬; 但其實就只是一點一點搭起來的而已。 指令並不可怕, 也不要覺得剪貼指令很不上進。 我就經常剪貼。 只要剪貼時勇敢地這裡改一點、 那裡改一點, 就會有收穫、 有感覺。 當資料量很大時, 下指令 vs 滑鼠選單的差別就很明顯了。 命令列控們堅持我們要用電腦, 不要被電腦用。
各種文字格式的檔案, 永遠是命令列控最好的朋友。 下指令時, regexp 很少是主角, 但經常是很重要的配角。 各種文字檔案處理工具也是。 學命令列就像玩積木一樣, 重點在於發揮組合的力量, 而不在於誰擁有哪一塊獨特、 稀有、 昂貴的積木。
沒有留言:
張貼留言
因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。