ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

ImageMagickをブラウザで動かしてみる

サーバーサイドエンジニアの本間です。 1年ぶりぐらいのブログへの投稿になりますね。久々の投稿、がんばろうと思います!

さて、弊社のサーバーサイドでメインで使っているプログラミング言語はRubyになります。 先日、3.2.0がリリースされ、WASIベースのWebAssembly(WASM)がサポートされました。 また、先日弊社の別メンバーから早速リリースされたRubyのWASMを使って、node.jsからRubyを動かしてみるという意欲的なエントリが投稿されました。

tech.unifa-e.com

そうした流れの中、自分も「WASMってどんなことができるのかな?」ということを試してみたくなりました。 何を試そう?と思った時、ImageMagickがWASMで使えるといろいろと便利だなと思い、ちょっと調べたところ有志の方によりWASMが作られて公開されていました。 今回、そのライブラリを使ってブラウザでImageMagickを使ってみたので、その内容を紹介しようと思います。

ブラウザでImageMagickを使う方法

百聞は一見にしかずということで、以下にサンプルで作ったページがあります。(初期表示に少し時間がかかります。最新のChrome推奨です)

https://ryusuke-homma-unifa.github.io/magick_wasm_test/index.html

このページで画像ファイルを読み込ませてみると、画像の情報を表示できたり、読み込んだ画像にリサイズやぼかしなどの処理ができると思います。 これはImageMagickのWASMを使い、全てブラウザ内で動作させています。

この静的サイトを生成するためのソースコードも以下に公開しています。

https://bitbucket.org/unifa-public/magick_wasm_test/

ImageMagickのWASM

公式の リンク一覧 を見ると、WebAssemblyのところに Magick.WASM(現: magick-wasm) がリンクされていました。 リポジトリを見てみたところ最近でもcommitが続いており、デモサイトもちゃんと動作したので、こちらを使用させていただくことにしました。

リポジトリのREADMEやデモサイトのソースを見たところ、npmパッケージとして配布されており、webpackで組み込んでの使用が想定されているようです。 デモサイトと同じくvue-cliを使って、組み込んでみようと思います。

vue create magick_wasm_test

cd magick_wasm_test

yarn add @imagemagick/magick-wasm

画像の読み込み

ここから先はドキュメントがほとんどない状況だったので、デモサイトから見よう見まねで対応しました。

まずImageMagickの初期化が必要のため initializeImageMagick をimportして呼び出しています。

import {
  ImageMagick,
  initializeImageMagick,
  Magick,
  Quantum,
} from '@imagemagick/magick-wasm';
export default defineComponent({
  setup() {
    initializeImageMagick().then(() => {
      // 初期化後にコンソールに情報表示
      console.log(Magick.imageMagickVersion);
      console.log('Delegates:', Magick.delegates);
      console.log('Features:', Magick.features);
      console.log('Quantum:', Quantum.depth);
    });
  }
});

画像の読み込みは、いくつか方法があるようなのですが、今回は ImageMagick.read に画像の生データが入った Uint8Array を渡す方法をとりました。

// <input type="file"/>のonchangeイベントで呼び出し
const loadImage = (e) => {
  const file = e.target.files[0]; // 画像ファイル

  const reader = new FileReader();
  reader.onload = (e) => {
    const buf = e.target.result; // 画像ファイルの生データ(ArrayBuffer)
    ImageMagick.read(new Uint8Array(buf), (image) => {
      // このimage(IMagickImage)が、ImageMagickを通していろいろできるオブジェクト
      image.writeToCanvas(canvas.value); // とりあえず読み込んだ画像をcanvasに表示
    })
  }
  reader.readAsArrayBuffer(file);
}

これで、無事画面に画像を表示できるようになりました。 ここで読み込んだ IMagickImage を使うことで、様々な処理ができるようになります。

画像の情報表示

ImageMagickで読み込んだ IMagickImage オブジェクトからは、画像のフォーマットや幅など様々な情報が取得できます。 以下にサンプルコードを示します。

image.format // => JPEG, PNGなどの画像フォーマット
image.width // => 画像の幅
image.height // => 画像の高さ
image.attributeNames // => exifなどの付加的な情報の属性名一覧

サンプルページでは、この方法で取得した情報を画面に表示しています。

読み込んだ画像の情報表示

取得可能な情報は、こちらを参照してください。

画像処理

さらに IMagickImage オブジェクトに対して、画像処理も簡単に行うことができます。

image.resize(500, 500) // 500x500にリサイズ
image.blur() // ぼかし
image.rotate(90) // 90度回転

image.writeToCanvas(canvas.value); // 処理した画像をcanvasに書き込んで表示

ぼかし、180度回転して、油彩画調にした例

操作可能な処理は、IMagickImageのメソッドを参照してください。

まとめ

今回、ImageMagickのWASMを使って、ブラウザで画像の情報を表示したり、画像処理をしてみたりしました。 ブラウザ内で画像に関する様々な処理が簡潔、かつサーバーサイドのリソースを使わずにできており、未来を感じることができました。

ただ、現在のバージョンが 0.0.18 ということからも分かる通り、まだまだ開発版という印象です。 ファイルサイズ自体が大きくなるため初期表示に時間がかかる点も気になりました。 今後のメンテナンス体制も含めて、まだ本番環境で使うのは早いかなと思いました。

以上になります。最後まで読んでいただき、ありがとうございました。

弊社では画像を使ったサービスが数多くあり、画像処理でいろいろやりたいエンジニアを鋭意募集中です。 気になったら、以下のページからご応募をお待ちしています!

unifa-e.com

参考サイト一覧

ImageMagick – Develop

GitHub - dlemstra/magick-wasm: The WASM library for ImageMagick

GitHub - dlemstra/magick-wasm-docs: Documentation for the @imagemagick/magick-wasm library

WebAssembly 版 ImageMagick 〜 magick-wasm の紹介 - Qiita