More Related Content
PDF
HTMLを書くだけで誰でも簡単!A-FrameではじめるWeb AR/VR PDF
PPTX
PPTX
PPTX
PPTX
PPTX
A-Framで始めるWebAR (Blenderハンズオンの続きver.) PPTX
Viewers also liked
PDF
zend_parse_parametersと64bit環境 PPTX
PDF
PDF
PPTX
PPTX
PPTX
PPTX
PPTX
Similar to GoImagickThumbnail
PDF
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像- PDF
PDF
PDF
PPTX
plenv時代のImageMagick && Image::Magickインストール方法 PPT
PDF
Fukuoka.php 第一回勉強会 LTスライド PPTX
GoImagickThumbnail
- 1.
- 2.
自己紹介 (@yoya)
• プロファイル
–https://osdn.jp/users/yoya/
• ImageMagick のストーカーしてます
– http://d.hatena.ne.jp/yoya/searchdiary?word=Im
ageMagick
• 昔、PHP でバイナリを弄ってました
– https://github.com/yoya/IO_MIDI
– https://github.com/yoya/IO_JPEG
• Golang は触り始めて一年ちょっと
?
- 3.
- 4.
- 5.
MagickWand と MagickCore
•GoImagick は MagickWand の関数を使う
ImageMagick
MagickCore
(magick)
coders
MagickWand
(wand)
utilities
画像処理
本体は
ココ
PerlMagick
PHP imagick
convert
コマンドはここ使い易くする
為のAPI
GoImagick
JPEGやPNG
の入出力
- 6.
つまり?
• convert コマンドとPHP imagick のコードを見る
と GoImagick の使い方も分かる
– convert コマンド
• wand/mogrify.c
– PHP imagick
• http://php.net/manual/ja/imagick.transformimage.php
- 7.
なぜ ImageMagick を使うのか?
•Golang 標準で image パッケージあるよね?
– 機能少ないし 対応形式は JPEG,GIF,PNG だけ
• libpng や jpeglib を直接使わないの?
– go-thumber がそうだけど cgo は難易度高い
• 他にも画像変換ツールがあるのでは?
– ImageMagick は困った時に検索で探しやすい
• (恐らく人による。自分は ImageMagick が楽)
- 8.
- 9.
- 10.
- 11.
GoImagick 導入 (MacOS編)
•少し前まで
• 今のやり方
$ sudo port install ImageMagick
$ go get github.com/gographics/imagick
# ImageMagick v6.8.8以前 (rpm や dpkg とかで古い場合)
$ go get gopkg.in/gographics/imagick.v1/imagick
# ImageMagick v6.8.9以降 (macports や最新版を使う場合)
$ go get gopkg.in/gographics/imagick.v2/imagick
以下のエラーが出ます
expects import "gopkg.in/gographics/imagick.v2/imagick"
- 12.
GoImagick 使用例
• resize640x480.go
_= 〜はエラーの値。ちゃんと拾って処理すべき
package main
import (
"gopkg.in/gographics/imagick.v2/imagick”
)
func main() {
imagick.Initialize()
defer imagick.Terminate()
mw := imagick.NewMagickWand()
defer mw.Destroy()
_ = mw.ReadImage(”input.png”)
_ = mw.ResizeImage(640, 480, imagick.FILTER_UNDEFINED, 1)
_ = mw.WriteImage("output.png")
}
- 13.
- 14.
アスペクト比を保つ方法(1/2)
• 出力サイズを変えてしまう
– はみ出ないように(内接)
• 480 × (250/340)
• => 352x480
• ResizeImage(352,480,…
– 減らさない (外接)
• 640 × (340/250)
• => 640x870
• ResizeImage(640,870,…
• ResizeImage だけで良い
250px
340px
480px
870px
640px
640px
352px
480px
- 15.
- 16.
マージン(内接)の方法
• 描画領域を広げる (ExtentImage)
–(640 – 352) / 2) = 144 ⇦ 左右に144拡げる
480px
640px
144px
640px
352px
480px 480px
352px
_ = mw.ResizeImage(352, 480, imagick.FILTER_UNDEFINED, 1)
_ = mw.ExtentImage(-144, 0, 640, 480) // -extents
_ = mw.ResetImagePage(“”) // +repage
- 17.
クロップ(外接)の方法(1/2)
• 描画領域を削る (ExtentImage)
–(640 – 352) / 2) = 144
_ = mw.ResizeImage(640, 870, imagick.FILTER_UNDEFINED, 1)
mw2 = mw.CropImage(0, 0, 640, 480) // -crop
defer mw2.Destory()
870px
640px 640px
480px480px
- 18.
- 19.
- 20.
画像合成
• CompositeImage で合成できる
_= mw1.ReadImage(“gopher.png”)
_ = mw2.ReadImage(“blind.png”)
_ = mw1.CompositeImage(mw2, imagick.COMPOSITE_OP_OVER, 45, 28)
CompositeImage
gopher.png
blind.png
- 21.
文字入れ (1/5)
• DrawingWandと PixelWand を使う
– DrawingWand でフォントを指定
• (日本語を表示するなら必須)
– (蛇足) QueryFont で扱えるフォントが分かる
dw := imagick.NewDrawingWand()
defer dw.Destroy()
_ = dw.SetFont("Noto-Sans-CJK-JP-Medium”)
dw.SetFontSize(24)
fonts := mw.QueryFont(“*”)
fmt.Printf(“%#v”, fonts)
- 22.
文字入れ (2/5)
• PixelWandで色を表現
• DrawingWand で色と文字を設定する
pw := imagick.NewPixelWand()
defer pw.Destroy()
_ = pw.SetColor(”rgb(0, 0, 0)”)
dw.SetFillColor(pw)
dw.Annotation(0, 0, “Gopher!!”)
- 23.
文字入れ (3/5)
• DrawingWandの文字を MagickWand の画像に
描画
• (0,0)を基準に文字を貼るので殆ど見えない
– 見えてるのは p の下にはみ出た部分
• Gravity 方式で配置しよう
_ = mw.DrawImage(dw) あれれ?
- 24.
文字入れ (4/5)
• CENTER指定と SOUTH 指定
dw.setGravity(imagick.GRAVITY_CENTER)
dw.Annotation(0, 0, “Gopher!!!”)
mw.DrawImage(dw)
GRAVITY_SOUTH
- 25.
文字入れ (5/5)
• まとめ
imagick.Initialize()
deferimagick.Terminate()
mw := imagick.NewMagickWand()
defer mw.Destroy()
dw := imagick.NewDrawingWand()
defer dw.Destroy()
pw := imagick.NewPixelWand()
defer pw.Destroy()
_ = mw.ReadImage(os.Args[1])
_ = dw.SetFont("Noto-Sans-CJK-JP-Medium")
dw.SetFontSize(24)
_ = pw.SetColor("rgb(255, 0, 0)")
dw.SetFillColor(pw)
dw.SetGravity(imagick.GRAVITY_CENTER)
dw.Annotation(0, 0, "Gopher!!!")
_ = mw.DrawImage(dw)
_ = mw.WriteImage("output.png”)
- 26.
MagickWand の注意点
• メソッドがMagickWand を返した時にも
Destroy が必要
– 中で new 相当の処理が動いてる
crop_src := “250x187+0+0”
geom_dst := “640x480”
mw2 = mw.TransformImage(crop_src, geom_dst)
defer mw2.Destroy()
_ = mw.ResizeImage(640, 870, imagick.FILTER_UNDEFINED, 1)
mw2 = mw.CropImage(0, 0, 640, 480) // -crop
defer mw2.Destory()
- 27.
GoImagick の中身
• 使うだけでなく中身も見よう
–https://github.com/gographics/imagick
imagick$ ls
CREDITS LICENSE env.sh imagick
History.md README.md examples
imagick$ ls imagick | wc
73 73 1298
imagick$ ls -R examples | wc
92 71 874
サンプルが沢山ある
GoImagick 本体
- 28.
- 29.
MagickWand と MagickCore
•おおまかな構造
ImageMagick
MagickCore
(magick)
coders
MagickWand
(wand)
utilities
画像処理
本体は
ココ
PerlMagick
PHP imagick
convert
コマンドはここ
使い易くする
為のAPI
GoImagick
???
JPEGやPNG
の入出力
- 30.
- 31.
- 32.
- 33.
最近のトピック
• メモリ管理を色々と修正 (byyoya)
– fixed to memory leak, string array issue.
• https://github.com/gographics/imagick/pull/37
• https://github.com/gographics/imagick/pull/39
• Magick.Initialize() に Mutex をかけたい(協議中)
– Fix Initialize/Terminate race condition #43
• https://github.com/gographics/imagick/pull/43
• MagickWand 等の回収を GC に任せたい
– Make mw, pi, pw, dw objects destroyable in GO GC #62
• https://github.com/gographics/imagick/pull/62
- 34.
メモリ管理を色々と修正 (1/3)
• フォント名一覧取得でメモリリークした
–似たような漏れが他にもあるのでは?
– Malloc してる箇所が見当たらないのに、free してるけ
どそのポインタは大丈夫なの?
• 関連するバグを調査
– 似たようなリークがあちこちにあった
• 文字列のリストを取得する系メソッドが大体ダメ
– Wand API の中で
AcquireMagickMemory(ImageMagick のメモリ管理)で
取得したメモリを、標準の free で解放してた
• RelinquishMemory を使うべき
- 35.
- 36.
- 37.
Magick.Initialize() に Mutex
•Magick.Initialize() や Terminate() をマルチス
レッドで呼ぶと競合するので Mutex をかけた
い
• Sync.once で Initialize を一度だけ呼べばよく
ない?
• でもユーザに気をつけろというより仕組みを
入れた方がよくない?
• 協議続行中
- 38.
GC に任せる(1/2)
• runtime.SetFinalizerを使う
• GC 対象になると SetFinalizer で指定したメソッ
ド(Destroy)が呼ばれる
func newMagickWand(mw *C.MagickWand) *MagickWand {
mw := &MagickWand{mw: cmw}
runtime.SetFinalizer(mw, Destroy)
mw.IncreaseCount()
return mw
}
- 39.
GCに任せる(2/2)
• defer でdestroy する問題点 (一般論)
– 毎回 defer 書くのは面倒だし忘れたりする
– 関数の外に return 出来ない
– 明示的に new するものはまだ良いけど、新しく
MagickWand を返すメソッドもあって漏れがち
• CropImage
• TransformImage
• これらの戻り値も Destroy しないとリークする
• defer mw.Destroy といちいち書かなくてもよく
なると嬉しい!
- 40.
まとめ
• MagickWand で画像を処理する
•DrawingWand で文字を描画する
• PixelWand で文字の色を指定する
• defer mw.Destroy() を忘れずに
– CropImage や TransformImage が返すのも Destroy() をお
忘れずに
• ここまでの話を聞けば、Golang でサムネール画像を
作れるはず
– Let’s try!