Node.js
canvas
bot
Slack

Slackで送った文字を画像で返すbot作った

More than 1 year has passed since last update.

ここでは

Slackで @textchan create 絵文字! と送ると、

絵文字!

という画像をアップしてくれるbotを作ってみる。

つくる理由

Slackで カスタム絵文字が多用されているようなチーム では、
文字だけを収めたカスタム絵文字が多く存在する。
またそれは、ユーザーの手作りであることが多い。

特にエンジニアが大活躍するようなところでは、
各エンジニアがPhotoshop等のデザインツールを持っていないことも珍しくないだろう。
カスタム絵文字の製作時間で職務に影響がでることは間違いない。効率化すべきである。

例)

/ 嬉しいときに


登校 / 登校したときに

何故、文字だけの絵文字が必要か

投稿に対して、すぐ読み取れるReactionを送ることができる
Reactionの例

今の気持ちとして、IDの横にStatusとして表示しておくことができる
Statusの例

つくる

テキストから画像を起こすという処理をするのあたり、
Node.js 上で canvas を生成できる node-canvasというのがいいと思った。
ウェブ上のJavaScriptで <canvas> を生成するのと同じ要領で使える。
のちのち、文字位置調整や、色、フォントの変更をする際も、比較的楽にできる。

また、Slack上で、Mentionを検知、画像をアップロードするために Botkit を使用する。

# node-canvas を動かすためのライブラリのインストール
# こちらは MacでHomebrewでインストールする場合
# その他 https://github.com/Automattic/node-canvas#installation
brew install pkg-config cairo pango libpng jpeg giflib

# node packageのインストール
npm install --save node-canvas botkit

参考にするもの

GitHub Repository 有り
Qiita上のコードは一部簡略化している

index.js
const Botkit = require('botkit')
const canvas = require('./canvas')

if (!process.env.token) {
  console.log('Error: Specify token in environment')
  process.exit(1)
}

const controller = Botkit.slackbot({
  debug: false
})

controller.spawn({
  token: process.env.token
}).startRTM(function (err) {
  if (err) {
    throw new Error(err)
  }
})

controller.hears('create(.*)', ['direct_message', 'direct_mention', 'mention'], function (bot, message) {
  var setting = {
    text: '',
    color: '#000',
    fontFamily: 'YuGothic'
  }

  var args = message.match[1]
  var reg = /\s+(["“”][^"“”]+["“”]|[^ ]+)/g
  var arg, i = 0

  while (arg = reg.exec(args)) {
    arg = arg[1].replace(/^["“”](.*)["“”]$/, '$1')

    switch (i) {
      case 0:
        setting.text = arg
        break
      case 1:
        setting.color = arg
        break
      case 2:
        setting.fontFamily = arg
        break
    }
    i++
  }

  canvas(setting).then(function (fileObj) {
    var messageObj = fileObj
    messageObj.channels = message.channel

    bot.api.files.upload(messageObj, function (err, res) {
      if (err) console.log(err)
    })
  })
})

▲Slack上でのMentionの検知や画像アップロードなどの処理などを記述

canvas.js
const Canvas = require('canvas')
const fs = require('fs')

var insertStr = function (str, index, insert) {
  return str.slice(0, index) + insert + str.slice(index, str.length);
}
var canvas_to_base64 = function (c) {
  return c.toDataURL().split(',')[1]
}
var decode_and_copy = function (string, filename) {
  return new Promise(function (resolve, reject) {
    var buffer = new Buffer(string, 'base64')
    fs.writeFile(filename, buffer, function (err) {
      if (err) {
        reject(err)
        return
      }
      resolve()
    })
  })
}

async function canvas(setting, next) {

  setting = setting || {
    text: 'えもじ!',
    color: '#000',
    fontFamily: 'YuGothic'
  }

  const text_n = insertStr(setting.text, 2, '\n')
  const filename = './' + setting.text + '.png'

  const c = new Canvas(128, 128)
  const ctx = c.getContext('2d')

  ctx.font = 'bold 60px ' + setting.fontFamily
  ctx.textAlign = 'center'
  ctx.fillStyle = setting.color
  ctx.fillText(text_n, 64, 56)

  await decode_and_copy(canvas_to_base64(c), filename)

  const fileObj = {
    file: fs.createReadStream(filename),
    filename: setting.text + '.png',
    title: setting.text
  }

  return fileObj
}

module.exports = canvas

▲テキストを画像にする処理を記述
今回は、全角4文字を 2文字・2文字の2行にする処理のみ

うごかす

# [Slack API Token] は適宜置き換え
token=[Slack API Token] node index.js
Slack
@textchan create 絵文字!
@textchan create 赤・明朝 red "YuMincho"

絵文字! 赤・明朝

恐らくこれらが返ってくるので
一旦ダウンロードし カスタム絵文字 として追加する

課題

  • 全角4文字以外でもキレイな画像を生成させる
  • canvasを一度画像ファイルで保存し、その画像ファイルを読み込んでいるが、恐らく不要な作業
  • 使用できるフォントが、マシンなりサーバーなりに依存する
  • 自動でカスタム絵文字追加させたい

おわり

楽しいカスタム絵文字ライフを。