Your posts match “ scale ” tag:

在 Ubuntu 上用 Ruby 寫一個縮圖工具

小小OS: 今天玩完後發現好好玩 XD ...

為了某個 Project 所以特別研究了一下步驟,這邊稍微做一下筆記。

這邊我會用 ImageMagick 當主要的縮圖工具,所以首先,我們不要使用 Ubuntu 自己的 ImageMagick ,而是直接上 ImageMagick 的官方網站下載最新版的來編譯,下載好後執行底下的指令再進行解壓縮原始碼的動作 (記得用 sudo or root 身份處理):

  1. apt-get remove imagemagick
  2. apt-get install libmagickcore-dev libmagickwand-dev

處理好後就可以開始解壓縮,然後用

  • ./configure
  • make
  • make install

來安裝 ImageMagick,並且在裝好後編輯 ~/.bash_profile 然後寫上 export LD_LIBRARY_PATH=/usr/local/lib ,這樣就可以了,退出 Shell 後重新登入就準備好了。

接下來,我們需要安裝 mini_magick 這個 Gem ... 不得不說這個東西真的超級好用 XD

你可以用 gem i mini_magick 安裝它,然後剩下的就是讀文件 http://rubydoc.info/github/minimagick/minimagick 就可以用了 XD

來寫一個圖片下載器好了 ... 下載好後可以縮成 800, 600, 400 三個尺寸的圖片

下載圖片

下載圖片可以透過 open-uri 這個 library 來處理,然後用

File.write(file_path, open(image_url).read, { mode: 'wb' })

就可以搞定,然後下載下來的圖片可以再用另外的工具去處理命名 ... 像是可以使用 SecureRandom.hex(15) 產生 30 個字的長度的亂數字串來產生 basename

改變圖片大小

透過 MiniMagick 我們可以很簡單的針對圖片進行一些處理,尤其是像是等比例縮放這種事情更是難不倒它!現在我們有個範例是我們會有三個不同寬度的尺寸準備用來轉換,所以我們可以先這樣做

image_sizes = [800, 600, 400]

然後寫一個變更圖片寬度的函式:

def resize(image_path, new_size)
  image = MiniMagick::Image.open image_path
  image.resize new_size
end

這樣只要透過 resize(image_path, 600) 就可以回傳一個被 resize 為寬度 600 的 image 物件,這時候可以透過 image.write(target_path) 就可以把圖片輸出到 target_path 去。

輸出不同尺寸圖片的檔案名稱

但是輸出圖片的時候我們需要有一個新的檔名,最好是 xxx_800.jpg 這種類型的名字,所以我們增加一個 function 來處理這件事。

def resize_name(image_path, size)
  ext_name = File.extname(image_path)
  filename = File.basename(image_path, ext_name)
  "#{filename}_#{size}#{ext_name}"
end

如此一來,我們可以用 resize_name("/tmp/helloworld.jpg", 300) 產生 /tmp/helloworld_300.jpg 這樣的名字了。

輸出圖片

在這邊我們改寫一下 resize function

def resize(image_path, new_size)
  image = MiniMagick::Image.open image_path
  image.resize new_size
  new_filename = resize_name(image_path, new_size)
  target_path = File.dirname(image_path)
  image.write File.join(target_path, new_filename)
end

這樣改寫後,就可以把圖片產生出尺寸後塞回原本的路徑底下,所以假設圖片原本是在 /tmp/helloworld.jpg 的話,我改成寬度 600px 就會產生到 /tmp/helloworld_600.jpg

針對多個尺寸進行轉換

這邊其實就很簡單,我們有 image_sizes 這個變數可以用,所以你可以在外面跑迭代或者把陣列傳到 resize 裡面去處理,這邊拿外部迭代做範例

image_path = "/tmp/helloworld.jpg"
image_sizes.each do |size|
  resize(image_path, size)
end

這樣就搞定了。

完整程式碼

def resize_name(image_path, size)
  ext_name = File.extname(image_path)
  filename = File.basename(image_path, ext_name)
  "#{filename}_#{size}#{ext_name}"
end

def resize(image_path, new_size)
  image = MiniMagick::Image.open image_path
  image.resize new_size
  new_filename = resize_name(image_path, new_size)
  target_path = File.dirname(image_path)
  image.write File.join(target_path, new_filename)
end

image_sizes = [800, 600, 400]
image_path = "/tmp/helloworld.jpg"
image_sizes.each do |size|
  resize(image_path, size)
end

大功告成

參考資料