友達と作っているtwitterのbotで、画像を合成してアップロードする機能が必要だったので、画像の合成について調べてみた。
環境
Node: v6.6.0
OS: Mac(OS X El Capitan)
GraphicsMagick のインストール
HomeBrew で入れられる。
brew install graphicsmagick
ImageMagick でも良いが、パフォーマンスはGraphicsMagick の方が良いらしい。
詳しくはググってほしい。
gm のインストール
GraphicsMagick のNode インタフェースをインストール。
npm install gm --save
画像の合成
画像の合成方法は、composite
というメソッドを使用する。
var gm = require('gm');
gm(baseImagePath)
.composite(setImagePath)
.geometry('+30+30')
.quality(100)
.write(newImagePath, function(err) {
if(err){
console.log(err)
}
})
baseImagePath
の上にsetImagePath
を乗せた画像がnewImagePath
に生成される。
geometry
は上に配置する画像の位置を指定しており、quality
は画像の圧縮率を指定している。
複数画像の合成(解決策1)
残念ながらcomposite
メソッドは複数画像を同時に配置することはできない。
もしやるとしたら非同期処理を繰り返し、生成された画像に対してまた画像を配置するということを繰り返す。
var gm = require('gm');
gm(baseImagePath)
.composite(setImage1Path)
.geometry('+30+30')
.quality(100)
.write(newImage1Path, function(err) {
if(err){
console.log(err)
}
gm(newImage1Path)
.composite(setImage2Path)
.geometry('+60+60')
.quality(100)
.write(newImage2Path, function(err) {
if(err){
console.log(err)
}
})
})
そして画像を生成する処理を繰り返すために、配置する画像が増えれば増えるほど処理が遅くなる。
ローカルで試したところ10枚ほどで10秒近くかかったと思う。
複数画像の合成(解決策2)
先に配置したい複数画像をすべて結合しておき、その結合画像をベースの画像に載せれば処理が非常に速くて済む。
var gm = require('gm');
var gmInstance = gm()
imagePathArray.forEach(function(imagePath){
gmInstance.montage(imagePath)
})
gmInstance
.transparent('white')
.tile('9x9')
.geometry('+0+0')
.quality(100)
.write(tmpImagePath, functiton(err) {
if(err){
console.log(err)
}
gm(baseImagePath)
.composite(tmpImagePath)
.geometry('+30+30')
.quality(100)
.write(imagePath, function(err) {
if(err){
console.log(err)
}
})
})
コツは結合した際の背景色をtransparent
で透明に指定すること。
各画像をそれぞれでおいたのと変わらなくなる。