我使用 carrierwave 來做圖片上傳,並使用產生器來生成 uploader,像這樣:
rails g uploader normal
會生成這樣的檔案:
class NormalUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
若想要在上傳圖片時,對圖片進行裁切操作,可以這樣寫:
class CropUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
process :crop
def crop
manipulate! do |img|
x = 1
y = 2
w = 3
h = 4
img.crop("#{w}x#{h}+#{x}+#{y}")
end
end
end
其中
include CarrierWave::MiniMagick
需要 gem "mini_magick" 以及 brew install imagemagick。
process :crop
這是一個 callback,會在圖片儲存前給你一個機會對圖片做事。所以只要前端傳遞一個矩形座標到後端就能切圖。這裡就隨便用 4 個值意思一下。
img.crop("#{w}x#{h}+#{x}+#{y}")
這個 crop 方法會被轉為系統指令
mogrify -crop 3x4+1+2 file_path
mogrify 是 imagemagick 提供的指令,可以拿它來切圖。
說明書在這裡:https://www.imagemagick.org/script/mogrify.php
一切運作良好,直到我遇到這張圖:https://www.ncl.ucar.edu/Applications/Images/color183_lg.png
怎麼切位置都是錯的。
強者我同事爬了一下文,發現是 ImageMagick 支援叫做 Virtual Canvas (虛擬圖層?)的資訊,這種東西其實是圖片的 Metadata 的一部分。
把出問題那張圖片拿去解析 Metadata:https://www.get-metadata.com/result/56d8b843-db53-4d7f-9f8a-7b1cd1ebde9b
會發現
Image Offset: 54, 64
也就是 ImageMagick 發現他有設定位移,所以就照這個設定去裁切了。然後用 +repage 可以讓他把 Offset 設回 0,0
所以這是我們的目標指令:
mogrify +repage -crop 3x4+1+2 file_path
但 ruby 是要這樣寫:
img.combine_options do |c|
c.repage.+
c.crop("#{w}x#{h}+#{x}+#{y}")
end
因為有兩個以上的參數,所以需要用 combine_options 去串接參數。
c.repage.+
會生成出
+repage
事實上他會把函數名稱拿去當作參數名稱,如果我這樣寫:
img.combine_options do |c|
c.jsdiofaodj.+
c.crop("#{w}x#{h}+#{x}+#{y}")
end
他就會嘗試執行
mogrify +jsdiofaodj -crop 199x154+234+343 file_path
如果把 .+ 拔掉:
img.combine_options do |c|
c.jsdiofaodj
c.crop("#{w}x#{h}+#{x}+#{y}")
end
就會變成
mogrify -jsdiofaodj -crop 199x154+234+343 file_path
如果調換順序:
img.combine_options do |c|
c.crop("#{w}x#{h}+#{x}+#{y}")
c.repage.+
end
會變成
mogrify -crop 3x4+1+2 +repage file_path
你可能會想說,參數順序有差嗎?還真的有差。
因為他不是參數順序,而是執行順序。
總而言之,強者我同事守護了世界的和平。
沒有留言:
張貼留言