2018/1/10
在 rails 上傳圖片並進行裁切時遭遇到的神奇問題
markdown
我使用 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.imagemagick.org/script/mogrify.php)
一切運作良好,直到我遇到這張圖:[https://www.ncl.ucar.edu/Applications/Images/color_18_3_lg.png](https://www.ncl.ucar.edu/Applications/Images/color_18_3_lg.png)
怎麼切位置都是錯的。
[強者我同事](https://blog.frost.tw)爬了一下文,發現是 ImageMagick 支援叫做 Virtual Canvas (虛擬圖層?)的資訊,這種東西其實是圖片的 Metadata 的一部分。
把出問題那張圖片拿去解析 Metadata:[https://www.get-metadata.com/result/56d8b843-db53-4d7f-9f8a-7b1cd1ebde9b](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
```
你可能會想說,參數順序有差嗎?還真的有差。
因為他不是參數順序,而是執行順序。
總而言之,[強者我同事](https://blog.frost.tw)守護了世界的和平。
參考資料:
[https://github.com/minimagick/minimagick/issues/107](https://github.com/minimagick/minimagick/issues/107)
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言