Node.jsのライブラリ Sharp でリサイズ

  • Web

このサイトのリニューアル以降、一部環境でスピードがどうにも上がらなかったため、取り急ぎ無駄に大きなリソースを最適化してみようと思い、まずはサムネイル画像をリサイズしてみることにしました。
しかしながら手動でやるのはとても面倒だったので、Node.jsのライブラリ Sharp を使ってみました。

What's Sharp

Sharpはnpmパッケージのみで完結している、シンプルな画像編集ライブラリです。
入力はJPEG、PNG、WebP、TIFF、SVG、GIFに対応していて、出力はJPEG、PNG、WebP、TIFFに対応しています。
リサイズ、拡大 / 縮小、トリミング、フォーマット変換、簡単な画像変換などは一通り網羅しているようです。
公式としてはこの手のツールとしては名高いImageMagickよりも4倍〜5倍速いとのことでした。

使用方法

インストール

yarnかnpmでインストールするだけです。
私はまだyarnを使用しているので、下記のように実行しました。

$ yarn add sharp

コード

使い方に関してはすでにいろんな人がブログに書いているので、そちらを参考にするといいかと思いますが、本当にシンプルで、以下のように処理を記述するだけです。
ここでは入力ファイルを指定していますが、ここにはBufferを渡すこともできるようです。

const sharp = require('sharp')
(() => {
  await sharp('input.jpg')
    .resize(null, 200)
    .toFile('output.jpg', (error, info) => {
      if (error) throw error
      console.info(info)
    })
})()

ちなみに上記の場合はアスペクト比を保ちつつ、高さが200pxになるようにリサイズするだけの処理です。
リサイズは基本的に resize() の引数をセットするだけである程度のことはできます。

横幅指定

sharp('input.jpg')
  .resize(200)
  .toFile('output.jpg')

高さ指定

sharp('input.jpg')
  .resize(null, 200)
  .toFile('output.jpg')

幅と高さ指定

幅と高さを指定する場合は、 resize の第3引数( options )に fit パラメータを指定することで、書き出し結果を変更させることができます。

sharp('input.jpg')
  .resize(null, 200, {
    fit: 'cover' // 'cover', 'contain', 'fill', 'inside', 'outside'
  })
  .toFile('output.jpg')
  • cover :アスペクト比を維持しつつ、縦中央部分が切り出される。デフォルト値
  • contain :アスペクト比を維持しつつ、指定サイズ内に収まるようにリサイズされる。余ったスペースには背景色で塗りつぶされる。(背景色は options で指定可能)
  • fill :アスペクト比を無視して指定したサイズになるようにリサイズ
  • inside :トリミングは行わず、アスペクト比を固定したまま指定サイズに収まるようにリサイズ
  • outside :トリミングは行わず、アスペクト比を固定したまま縦横いずれかが指定サイズになるようにリサイズ

どう使ったのか

あらためて私が今回やりたかったことは、ブログのアイキャッチ画像などのサムネイル自動生成です。
なので、下記のようなスクリプトを用意して、特定のディレクトリ配下の画像に対してサムネイル生成を行うようにしました。

glob('./src/img/blog/*', (err, files) => {
  if (!fs.existsSync('./src/img/blog/thumbnail')) {
    fs.mkdirSync('./src/img/blog/thumbnail')
  }

  files.forEach(file => {
    const basename = path.basename(file)
    const extname = path.extname(file)
    const filename = path.basename(file, extname)

    if (!/^.*?\..*?$/.test(basename)) return

    sharp(file)
      .resize(null, 195)
      .toFile(`./src/img/blog/thumbnail/${filename}${extname}`, (err, info) => {
        if (err) throw err
        console.log(info)
      })
    ...
  })
})

実行するタイミングについては、このサイトはデプロイ時に各画像の最適化を行なっていたので、その最適化の後に実行するようにしてみました。

"scripts": {
  "imagemin": "npm run ./node_task/imagemin.js", // 画像最適化
  "create_thumbnail": "npm run ./node_tasks/create_thumbnail.js", // 今回定義したサムネイル生成スクリプト
  "build_image": "npm run imagemin && npm run create_thumbnail",
  ...
}

これで記事を書いた時にわざわざ自分でサムネイル画像を作らなくて済むようになりました。
WordPressからVuePressに移行した時からのちょっとした悩みポイントだったのですが、Sharpがあっさりと解決してくれました。

まとめ

今回はリサイズのみで使いましたが、これ以外にもblurやsharpnessなどの画像変換にも対応していて、割と便利そうな印象を受けました。
コードもとてもシンプルに書くことができるので、初心者にも優しいのではないでしょうか。

もっと細かい仕様を知りたい方は、ぜひ公式のGitHubリポジトリを覗いてみてください。

https://github.com/lovell/sharp