Ruby + Pipe 的用法:圖片辨識與過濾


#1

抱歉沉寂的時間有點久,最近在弄些人生大事有點忙哈哈 … 而這邊的改名計畫(RailsFun => devFun)應該五月開始進行就是

大概就是最近在寫公司的一些 lib 和交易核心的東西,有些東西牽涉到加密和系統安全,無法公開展示,所以只能少部分的公開些我認為 ok 的內容就是了

今天有的需求,使用者使用 APP 上傳他個人證件來讓客服人員來做 KYC 驗證,流程類似

APP(拍照Photo) => Base64(JSON) => API => ( 辨識 / 過濾 / 轉圖 ) => 加密[多重簽章] => 儲存

今天要談的是 ( 辨識 / 過濾 / 轉圖 ) 的部分,因為東西有嚴重的機敏性(畢竟是客戶的個資啊…),除非"儲存`階段才能留檔,這樣中間過濾怎樣完成?

先貼完整的 demo code 在這邊 pipe_image_opt.rb.zip (2.4 KB)

以 Paperclip 的安全性而言基本上會過三個動作:(關於 Paperclip 請善用站內搜尋功能…)

file -b --mime '/file_path/test.png'
identify -format '%wx%h,%[exif:orientation]' '/file_path/test.png[0]' 2>/dev/null
convert '/file_path/test.png[0]' -auto-orient -resize "2048x2048>" -coalesce -colorspace sRGB -quality 70 '/file_path/target.jpg'

分別是:

file 檢查原始資料的 header 判定型別
identify ( imagemagick ) 檢查圖片原始資訊
convert  ( imagemagick ) 轉圖,清除圖片挾帶的垃圾或惡意程式

所以自己寫的程式也需要才行,但要求是 “不留檔”

不留檔在 linux 下其實很好製作的,關鍵字會是 pipe,而 pipe 其實就是 stdin / stdout 的連續技而已,你常可以看到類似 linux 用這種指令

ls | grep -c '.' #把 ls 出來的字串計算有多少個 '.'

以 ls 來說輸出的是 stdout,而用 | pipe 符號可以變成下個程式的 stdin,這樣就可以持續的串接下去之類的,而 Ruby call system 當然也可以完成,不過你無法使用

` ` 同 %x%% 或 system()

因為這兩個都無法讓你用 pipe 的 stdin,而如果用 <> 則一定是檔案才行,類似

mysqldump > backup.sql #把 stdout 變成檔案
mysql < backup.sql #把檔案變成 stdin

雖然這樣可以操作 stdin / stdout,但…其實已經存擋了不是?所以此路不通,而 Ruby 這類控制最好用的還是 Open3 系列,尤其是 capture3

https://apidock.com/ruby/Open3/capture3/class

用這個你一次可以取到熱騰騰的 stdout / stderr / status ,參數也可以指定 stdin,類似裡面的 demo

thumnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
if s.success?
  STDOUT.binmode; print thumnail
end

這不就是我們要的嗎 : )

其餘就還好了,只是指令設定和流程的問題而已,而強者我朋友也有提到,shell 使用 - 可以取代檔案名稱變成 stdin,所以這樣任何指令其實都可以吃 stdin,類似

> file test.png
#=> test.png: PNG image data, 1000 x 1333, 8-bit/color RGB, non-interlaced
> cat test.png | file -
#=> /dev/stdin: PNG image data, 1000 x 1333, 8-bit/color RGB, non-interlaced
#用 cat 把資料變成 stdout 餵給 file,file 把 stdin 當作檔案輸入

很酷炫不是嗎?所以參考我的程式,把三個指令的 stdin / stdout 處理好就可以開心的不留檔,然後串下去了哩

對了,這支程式我把 identify 改成了 exiftool,可以取到些有趣的東西,類似手機型號和 GPS,玩看看唄 X"D

以上


詢問sinatra與rest-client
如何在client端壓縮圖片並將資料送到後端