SlideShare a Scribd company logo
1 of 40
GoImagick でサムネール作成
〜 Golang & ImageMagick 〜
2016年4月8日(金)
“よや” yoya@awm.jp
自己紹介 (@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 は触り始めて一年ちょっと
?
GoImagick とは
• https://github.com/gographics/imagick
• MagickWand API (C言語)の Go バインディング
– Go 言語で ImageMagick の機能が使えます
公式サイトからもリンク
• http://imagemagick.org/script/api.php#go
• MagickWand と MagickCore の Go バインディ
ング
– GoImagick はMagickCore の定義を取り入れるけ
ど、関数は MagickWand のだけ使います。
MagickWand と MagickCore
• GoImagick は MagickWand の関数を使う
ImageMagick
MagickCore
(magick)
coders
MagickWand
(wand)
utilities
画像処理
本体は
ココ
PerlMagick
PHP imagick
convert
コマンドはここ使い易くする
為のAPI
GoImagick
JPEGやPNG
の入出力
つまり?
• convert コマンドと PHP imagick のコードを見る
と GoImagick の使い方も分かる
– convert コマンド
• wand/mogrify.c
– PHP imagick
• http://php.net/manual/ja/imagick.transformimage.php
なぜ ImageMagick を使うのか?
• Golang 標準で image パッケージあるよね?
– 機能少ないし 対応形式は JPEG,GIF,PNG だけ
• libpng や jpeglib を直接使わないの?
– go-thumber がそうだけど cgo は難易度高い
• 他にも画像変換ツールがあるのでは?
– ImageMagick は困った時に検索で探しやすい
• (恐らく人による。自分は ImageMagick が楽)
ImageMagick を使う理由(1/2)
• 画像を処理したいメソッドが大体揃っている
– リサイズ
– フィルタ
– 画像合成
– 文字入れ Gopher
ImageMagick を使う理由(2/2)
• メジャーな画像フォーマットからマイナーなものま
で100種類以上に対応してる
• http://www.imagemagick.org/script/formats.php
png
jpeg
gif
inline
sixel
webp
svg
pdf
超メジャー 最近の
キワモノ系
(Webの base64画像とか)
ベクター画像
dcm
医療系
(DICOM等)
ここから本題
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"
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")
}
ResizeImage(640,480,… 実行
• 縦横のアスペクト比が…
– サムネール画像としてはNG
$ go run resize640x480.go gopher.png
250px
340px
480px
640px
ふくよかな
Gopher!
アスペクト比を保つ方法(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
アスペクト比を保つ方法(2/2)
• 出力サイズを変えない
– マージンをつける (内接)
• 480 × (250/340)
• => 352x480
– クロップする (外接)
• 640 × (340/250)
• => 640x870
• ResizeImage だけでは無理
250px
340px
480px
870px
640px
640px352px
480px
マージン(内接)の方法
• 描画領域を広げる (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
クロップ(外接)の方法(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
クロップ(外接)の方法(2/2)
• リサイズとクロップ同時 (TransformImage)
– 250 × (480/640) = 187.5
crop_src := “250x187+0+0”
geom_dst := “640x480”
mw2 = mw.TransformImage(crop_src, geom_dst)
defer mw2.Destroy()
640px
480px
250px
340px
187px
マージンやクロップの注意点
• マージンをどこに
つけるか、どこを
クロップするか
は画像次第
250px
340px
480px
870px
640px
640px
352px
480px
640px 352px
870px
480px
画像合成
• CompositeImage で合成できる
_ = mw1.ReadImage(“gopher.png”)
_ = mw2.ReadImage(“blind.png”)
_ = mw1.CompositeImage(mw2, imagick.COMPOSITE_OP_OVER, 45, 28)
CompositeImage
gopher.png
blind.png
文字入れ (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)
文字入れ (2/5)
• PixelWand で色を表現
• DrawingWand で色と文字を設定する
pw := imagick.NewPixelWand()
defer pw.Destroy()
_ = pw.SetColor(”rgb(0, 0, 0)”)
dw.SetFillColor(pw)
dw.Annotation(0, 0, “Gopher!!”)
文字入れ (3/5)
• DrawingWand の文字を MagickWand の画像に
描画
• (0,0)を基準に文字を貼るので殆ど見えない
– 見えてるのは p の下にはみ出た部分
• Gravity 方式で配置しよう
_ = mw.DrawImage(dw) あれれ?
文字入れ (4/5)
• CENTER 指定と SOUTH 指定
dw.setGravity(imagick.GRAVITY_CENTER)
dw.Annotation(0, 0, “Gopher!!!”)
mw.DrawImage(dw)
GRAVITY_SOUTH
文字入れ (5/5)
• まとめ
imagick.Initialize()
defer imagick.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”)
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()
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 本体
ところで
• http://imagemagick.org/script/api.php#go
• なぜ GoImagick と ImageMagick本家で説明に
食い違いがあるのか。
• なぜ GoImagick と ImageMagick本家で説明に
食い違いがあるのか
– GoImagick ⇨ MagickWand
– ImageMagick本家 ⇨ MagickWand + MagickCore
MagickWand と MagickCore
• おおまかな構造
ImageMagick
MagickCore
(magick)
coders
MagickWand
(wand)
utilities
画像処理
本体は
ココ
PerlMagick
PHP imagick
convert
コマンドはここ
使い易くする
為のAPI
GoImagick
???
JPEGやPNG
の入出力
grep include * で確認
• はい。MagickCore も include してます
MagickCore の利用例
• 型の定義を取り込みたいだけ。MagickCore
の関数を利用してる訳ではなさそう
つまりどういう事?
• 利用する関数は MagickWand だけ
– MagickCore ではない (型の取り込みで include し
てるだけ)
• PerlMagick より PHP imagick のサンプルが参
考になるという事
最近のトピック
• メモリ管理を色々と修正 (by yoya)
– 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
メモリ管理を色々と修正 (1/3)
• フォント名一覧取得でメモリリークした
– 似たような漏れが他にもあるのでは?
– Malloc してる箇所が見当たらないのに、free してるけ
どそのポインタは大丈夫なの?
• 関連するバグを調査
– 似たようなリークがあちこちにあった
• 文字列のリストを取得する系メソッドが大体ダメ
– Wand API の中で
AcquireMagickMemory(ImageMagick のメモリ管理)で
取得したメモリを、標準の free で解放してた
• RelinquishMemory を使うべき
メモリ管理を色々と修正 (2/3)
• 調査した
• O 以外が
不具合の
あるメソッド
メモリ管理を色々と修正 (3/3)
• 結構大量に修正
– 余計な修正をcommitしちゃったけどマージしてく
れた
– CREDITS に名前載せてくれた
やさしい
Magick.Initialize() に Mutex
• Magick.Initialize() や Terminate() をマルチス
レッドで呼ぶと競合するので Mutex をかけた
い
• Sync.once で Initialize を一度だけ呼べばよく
ない?
• でもユーザに気をつけろというより仕組みを
入れた方がよくない?
• 協議続行中
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
}
GCに任せる(2/2)
• defer で destroy する問題点 (一般論)
– 毎回 defer 書くのは面倒だし忘れたりする
– 関数の外に return 出来ない
– 明示的に new するものはまだ良いけど、新しく
MagickWand を返すメソッドもあって漏れがち
• CropImage
• TransformImage
• これらの戻り値も Destroy しないとリークする
• defer mw.Destroy といちいち書かなくてもよく
なると嬉しい!
まとめ
• MagickWand で画像を処理する
• DrawingWand で文字を描画する
• PixelWand で文字の色を指定する
• defer mw.Destroy() を忘れずに
– CropImage や TransformImage が返すのも Destroy() をお
忘れずに
• ここまでの話を聞けば、Golang でサムネール画像を
作れるはず
– Let’s try!

More Related Content

Viewers also liked

コンピュータ画像うんちく
コンピュータ画像うんちくコンピュータ画像うんちく
コンピュータ画像うんちくYo Ya
 
chokaizomae
chokaizomaechokaizomae
chokaizomaeYo Ya
 
zend_parse_parametersと64bit環境
zend_parse_parametersと64bit環境zend_parse_parametersと64bit環境
zend_parse_parametersと64bit環境Yo Ya
 
PHP AV BINDING
PHP AV BINDINGPHP AV BINDING
PHP AV BINDINGYo Ya
 
PHPでのSWF編集とその応用
PHPでのSWF編集とその応用PHPでのSWF編集とその応用
PHPでのSWF編集とその応用Yo Ya
 
PHP でバイナリ変換プログラミング
PHP でバイナリ変換プログラミングPHP でバイナリ変換プログラミング
PHP でバイナリ変換プログラミングYo Ya
 
php5-gd で画像を弄る話
php5-gd で画像を弄る話php5-gd で画像を弄る話
php5-gd で画像を弄る話Yo Ya
 
退職PDFメーカーの作り方
退職PDFメーカーの作り方退職PDFメーカーの作り方
退職PDFメーカーの作り方Yo Ya
 
How to read SWF
How to read SWFHow to read SWF
How to read SWFYo Ya
 

Viewers also liked (9)

コンピュータ画像うんちく
コンピュータ画像うんちくコンピュータ画像うんちく
コンピュータ画像うんちく
 
chokaizomae
chokaizomaechokaizomae
chokaizomae
 
zend_parse_parametersと64bit環境
zend_parse_parametersと64bit環境zend_parse_parametersと64bit環境
zend_parse_parametersと64bit環境
 
PHP AV BINDING
PHP AV BINDINGPHP AV BINDING
PHP AV BINDING
 
PHPでのSWF編集とその応用
PHPでのSWF編集とその応用PHPでのSWF編集とその応用
PHPでのSWF編集とその応用
 
PHP でバイナリ変換プログラミング
PHP でバイナリ変換プログラミングPHP でバイナリ変換プログラミング
PHP でバイナリ変換プログラミング
 
php5-gd で画像を弄る話
php5-gd で画像を弄る話php5-gd で画像を弄る話
php5-gd で画像を弄る話
 
退職PDFメーカーの作り方
退職PDFメーカーの作り方退職PDFメーカーの作り方
退職PDFメーカーの作り方
 
How to read SWF
How to read SWFHow to read SWF
How to read SWF
 

Similar to GoImagickThumbnail

Lecuture on Deep Learning API
Lecuture on Deep Learning APILecuture on Deep Learning API
Lecuture on Deep Learning APINaoki Watanabe
 
vImageのススメ(改訂版)
vImageのススメ(改訂版)vImageのススメ(改訂版)
vImageのススメ(改訂版)Shuichi Tsutsumi
 
HTML5のCanvas入門 - Img画像を編集してみよう -
HTML5のCanvas入門 - Img画像を編集してみよう -HTML5のCanvas入門 - Img画像を編集してみよう -
HTML5のCanvas入門 - Img画像を編集してみよう -Toshio Ehara
 
SVGでつくるインタラクティブWebアプリケーション
SVGでつくるインタラクティブWebアプリケーションSVGでつくるインタラクティブWebアプリケーション
SVGでつくるインタラクティブWebアプリケーションKohei Kadowaki
 
03 piggyback -by-simple-code-public
03 piggyback -by-simple-code-public03 piggyback -by-simple-code-public
03 piggyback -by-simple-code-publicSmz Nbys
 
株式会社インタースペース 清水様 登壇資料
株式会社インタースペース 清水様 登壇資料株式会社インタースペース 清水様 登壇資料
株式会社インタースペース 清水様 登壇資料leverages_event
 
忙しい人はSimplicityテーマに丸投げ
忙しい人はSimplicityテーマに丸投げ忙しい人はSimplicityテーマに丸投げ
忙しい人はSimplicityテーマに丸投げYuki Okamoto
 
3DCG(3Dコンピュータグラフィック)をWebGLで始めよう
3DCG(3Dコンピュータグラフィック)をWebGLで始めよう3DCG(3Dコンピュータグラフィック)をWebGLで始めよう
3DCG(3Dコンピュータグラフィック)をWebGLで始めようAdvancedTechNight
 
Emscripten night "WebGL + WASM"
Emscripten night "WebGL + WASM"Emscripten night "WebGL + WASM"
Emscripten night "WebGL + WASM"翔 石井
 
スマホにおけるWebGL入門
スマホにおけるWebGL入門スマホにおけるWebGL入門
スマホにおけるWebGL入門Yohta Kanke
 
from old HTML to modern HTML
from old HTML to modern HTMLfrom old HTML to modern HTML
from old HTML to modern HTMLxyzplus_net
 
Html5 canvasとgoogle maps apiで遊んでみた
Html5 canvasとgoogle maps apiで遊んでみたHtml5 canvasとgoogle maps apiで遊んでみた
Html5 canvasとgoogle maps apiで遊んでみた真吾 森
 
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-昌彦 飛騨
 
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2moto2g
 
シェーダーしよっ☆ Let's play shaders!
シェーダーしよっ☆ Let's play shaders!シェーダーしよっ☆ Let's play shaders!
シェーダーしよっ☆ Let's play shaders!Yuichi Higuchi
 
Viewのキャプチャを撮ってみる
Viewのキャプチャを撮ってみるViewのキャプチャを撮ってみる
Viewのキャプチャを撮ってみるYoshihiro Wada
 
Cocos2d x-sprite3d
Cocos2d x-sprite3dCocos2d x-sprite3d
Cocos2d x-sprite3daktsk
 
Introduce build in shrinker
Introduce build in shrinkerIntroduce build in shrinker
Introduce build in shrinkerDaisuke Fuji
 
インラインSVGをつかって地図っぽいものをつくってみる
インラインSVGをつかって地図っぽいものをつくってみるインラインSVGをつかって地図っぽいものをつくってみる
インラインSVGをつかって地図っぽいものをつくってみるKohei Kadowaki
 

Similar to GoImagickThumbnail (20)

Lecuture on Deep Learning API
Lecuture on Deep Learning APILecuture on Deep Learning API
Lecuture on Deep Learning API
 
vImageのススメ(改訂版)
vImageのススメ(改訂版)vImageのススメ(改訂版)
vImageのススメ(改訂版)
 
HTML5のCanvas入門 - Img画像を編集してみよう -
HTML5のCanvas入門 - Img画像を編集してみよう -HTML5のCanvas入門 - Img画像を編集してみよう -
HTML5のCanvas入門 - Img画像を編集してみよう -
 
SVGでつくるインタラクティブWebアプリケーション
SVGでつくるインタラクティブWebアプリケーションSVGでつくるインタラクティブWebアプリケーション
SVGでつくるインタラクティブWebアプリケーション
 
Grimoire.js + HoloLens
Grimoire.js + HoloLensGrimoire.js + HoloLens
Grimoire.js + HoloLens
 
03 piggyback -by-simple-code-public
03 piggyback -by-simple-code-public03 piggyback -by-simple-code-public
03 piggyback -by-simple-code-public
 
株式会社インタースペース 清水様 登壇資料
株式会社インタースペース 清水様 登壇資料株式会社インタースペース 清水様 登壇資料
株式会社インタースペース 清水様 登壇資料
 
忙しい人はSimplicityテーマに丸投げ
忙しい人はSimplicityテーマに丸投げ忙しい人はSimplicityテーマに丸投げ
忙しい人はSimplicityテーマに丸投げ
 
3DCG(3Dコンピュータグラフィック)をWebGLで始めよう
3DCG(3Dコンピュータグラフィック)をWebGLで始めよう3DCG(3Dコンピュータグラフィック)をWebGLで始めよう
3DCG(3Dコンピュータグラフィック)をWebGLで始めよう
 
Emscripten night "WebGL + WASM"
Emscripten night "WebGL + WASM"Emscripten night "WebGL + WASM"
Emscripten night "WebGL + WASM"
 
スマホにおけるWebGL入門
スマホにおけるWebGL入門スマホにおけるWebGL入門
スマホにおけるWebGL入門
 
from old HTML to modern HTML
from old HTML to modern HTMLfrom old HTML to modern HTML
from old HTML to modern HTML
 
Html5 canvasとgoogle maps apiで遊んでみた
Html5 canvasとgoogle maps apiで遊んでみたHtml5 canvasとgoogle maps apiで遊んでみた
Html5 canvasとgoogle maps apiで遊んでみた
 
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-
SappoRoR#7 Rを用いた画像処理入門 -胸部X線の経時的差分画像-
 
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2
DCGANとStyleGAN2を試したときの話 / Dcgan and Stylegan2
 
シェーダーしよっ☆ Let's play shaders!
シェーダーしよっ☆ Let's play shaders!シェーダーしよっ☆ Let's play shaders!
シェーダーしよっ☆ Let's play shaders!
 
Viewのキャプチャを撮ってみる
Viewのキャプチャを撮ってみるViewのキャプチャを撮ってみる
Viewのキャプチャを撮ってみる
 
Cocos2d x-sprite3d
Cocos2d x-sprite3dCocos2d x-sprite3d
Cocos2d x-sprite3d
 
Introduce build in shrinker
Introduce build in shrinkerIntroduce build in shrinker
Introduce build in shrinker
 
インラインSVGをつかって地図っぽいものをつくってみる
インラインSVGをつかって地図っぽいものをつくってみるインラインSVGをつかって地図っぽいものをつくってみる
インラインSVGをつかって地図っぽいものをつくってみる
 

GoImagickThumbnail