はじめに
ドラム譜を作成しようと思いMuseScoreというのを使って楽譜を作成したんですが、書いた楽譜のスクリーンショットを撮るとこんな感じになります
こういう白背景(厳密には真っ白ではないが)の楽譜の背景を透明にしたい場合、いろいろな方法があると思いますが今回はJavascriptを使って行ってみました。
最終的に背景を透明にした画像はこの様に重ねて使えるようになります。
使うもの
上についてわからないものがあれば、Googleで調べてから再度ここにきてください。僕の過去の記事でも説明しているものがあると思うので参考にしてみてください。
書いたコード
const fs = require('fs')
const PNG = require('pngjs').PNG
fs.createReadStream('path/to/your.png')
.pipe(new PNG())
.on("parsed", function() {
for (let y = 0; y < this.height; y++) {
for (let x = 0; x < this.width; x++) {
const index = (this.width * y + x) << 2;
const r = this.data[index]
const g = this.data[index + 1]
const b = this.data[index + 2]
if (r + g + b > 255 / 2 * 3) {
this.data[index + 3] = 0
}
}
}
this.pack().pipe(fs.createWriteStream('path/to/your/output.png'))
})
解説
まずはpngjsのドキュメントを読みます。
最初からゴールが見えた様な状態のサンプルが書いてあったので、それを使いますが、前提知識として。
我々が普段使っているディスプレイは、1ピクセルという単位があり、1つのLEDのようなものです。例えばFullHDのディスプレイだと横に1920個・縦に1080個並んでいて、これらの色加減によって我々は画像を認識しています。
PNGの場合、1ピクセルは赤(red)・緑(green)・青(blue)・透明度(alpha)と言う4種類の単位で表現されます。rgbaとか言ったりしますね。
そして、データ上は先頭から[1ピクセル目のr][1ピクセル目のg][1ピクセル目のb][1ピクセル目のa][2ピクセル目のr][2ピクセル目のg]...
という様に配列に格納されています。
それぞれ0~255までの256個の整数で構成されています。
ただこれだと全てのデータが横一列に並んでいるため、二次元の画像として使うためには高さ(width)と横幅(height)の情報が必要です。これもPNGファイルに含まれていて、その辺りはpngjsがうまいこと読み込んで処理してくれているのでこちらが考えることはrgbaデータをどの様に加工するかです。
ここまでが前提知識で、今回やりたかった白背景を透明にする部分ですが、途中にif (r + g + b > 255 / 2 * 3) {
と書いた行があり、この条件式は白に近い色
を判定するためのもので、この後の行this.data[index + 3] = 0
の部分が透明にする処理です。
あとはサンプル通りですがファイルパスを正しく書き換えれば出力してくれます。
おわりに
正直このコード書くより記事書く方が1000倍大変です。。。
ちなみにですが、この条件式と背景処理だと、出力される画像が若干ジャギーになってしまいます(丸みを帯びた物(音符)を表現するために、丸い部分は曖昧な色が使われているため)。
なので、もっと滑らかに透明にしたい場合は条件式と後処理にもっと手を加える必要がありますね。