0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Active Storage の画像処理から libvips / ImageMagick を消す Pure Ruby gem を作った

0
Last updated at Posted at 2026-04-21

Update (2026-04-23): v0.3.0 で最後の gem 依存(image_processing)も削除し、文字通りゼロ依存になりました。さらに ブラウザで動くプレイグラウンド も公開。ImageProcessing::Pura のチェインがブラウザタブ内で ruby.wasm 経由で動きます。

TL;DR

Pure Ruby 製の画像処理 gem pura-image を作りました。これを image_processing gem の variant_processor として指定すると、Rails Active Storage の画像処理から libvips / ImageMagick / ffmpeg を完全に取り除けます

# Gemfile
  gem "image_processing"
+ gem "pura-image"
# config/application.rb
config.active_storage.variant_processor = :pura
# Dockerfile
- RUN apt-get install -y libvips-dev imagemagick

brew install vipsapt install imagemagick も不要。gem install pura-image するだけで動きます。

ブラウザで試せます

文章を読む前に動く様子を見たい方はこちら:

komagata.github.io/pura-image

ページを開くと ruby.wasm が起動し、ImageProcessing::Pura のチェインがブラウザ内で実行されます。Rails Active Storage の variant 定義に書くコードと同じものが、サーバーに何も送らずにブラウザタブ内で走ります。

正確に言うと、ブラウザで動くのは ImageProcessing::Pura の処理チェイン部分だけで、Active Storage 本体(blob 管理や variant orchestration)は動いていません。それでも「Rails の variant コードが wasm サンドボックスで動く」のを目で見て確認できます。

対象読者

  • Rails アプリで Active Storage を使っている開発者
  • Docker イメージから libvips / ImageMagick を抜きたい人
  • CI の apt-get install 行を削りたい人
  • Windows / WSL での Rails 環境構築に苦しんだことがある人
  • 新人教育で「brew install vips でつまずいた人」を見たことがある人

なぜ作ったか

プログラミング初学者に Rails を教えていると、rails new した直後の画像アップロード機能のセットアップでつまずく人が多くいます。Mac なら brew install vips、Linux なら apt install libvips-dev、Windows ならまた別の手順… と OS ごとに分岐するうえ、ビルドエラーで詰まることも多く、本題に入る前に脱落者が出てしまいます。

「Pure Ruby だけで動けばこの問題は全部消えるのでは?」というのが出発点です。同時に、業務 Rails アプリでも以下のメリットがあります。

  • Docker イメージが軽くなる: libvips / ImageMagick / その依存ライブラリが丸ごと不要
  • CI が速くなる: apt-get install のオーバーヘッドが消える
  • デプロイ環境を選ばない: Heroku / Fly.io / Render など PaaS でも追加 buildpack 不要
  • Edge / Wasm 環境で動く: ruby.wasm 上でも画像処理ができる(ブラウザデモ

対応フォーマット

JPEG / PNG / BMP / GIF / TIFF / ICO・CUR / WebP の 7 形式すべてを Pure Ruby で実装しています。マジックバイトでフォーマットを自動判定するので、拡張子に頼る必要はありません。

Format Decode Encode
JPEG
PNG
BMP
GIF
TIFF
ICO/CUR
WebP

v0.3.0 では image_processing gem への依存も切って、自作の pura-processing に置き換えました。これで本当に外部 gem ゼロです。

使い方

単体での利用

require "pura-image"

# どの形式でもマジックバイトで自動判定して読み込み
image = Pura::Image.load("photo.jpg")
image.width   #=> 800
image.height  #=> 600

# 拡張子から保存形式を決定
Pura::Image.save(image, "output.png")

# メソッドチェイン
Pura::Image.load("photo.jpg")
  .resize_to_limit(800, 600)
  .rotate(90)
  .grayscale

Rails Active Storage との統合

image_processing gem 互換のアダプタを同梱しているので、設定 1 行で切り替わります。モデルやビューの記述は一切変更不要。

# Gemfile
gem "image_processing"
gem "pura-image"
# config/application.rb
config.active_storage.variant_processor = :pura

既存のコードはそのまま動きます。

class User < ApplicationRecord
  has_one_attached :avatar do |attachable|
    attachable.variant :thumb, resize_to_limit: [200, 200]
  end
end
<%= image_tag user.avatar.variant(:thumb) %>

サポートしている操作

image_processing gem の主要 API はひととおり実装しています。

image = Pura::Image.load("photo.jpg")

image.resize_to_limit(800, 600)   # 縮小のみ、アスペクト比維持
image.resize_to_fit(400, 400)     # フィット、アスペクト比維持
image.resize_to_fill(400, 400)    # 指定サイズに塗りつぶし、はみ出し中央クロップ
image.resize_and_pad(400, 400)    # フィット後、余白を黒で埋める
image.resize_to_cover(400, 400)   # カバー、クロップなし

image.crop(10, 10, 200, 200)      # 領域クロップ
image.rotate(90)                   # 90 / 180 / 270 度回転
image.grayscale                    # グレースケール変換

ベンチマーク(vs ffmpeg)

400×400 画像、Ruby 4.0.2 + YJIT 環境で計測しました。

Decode

Format pura-* ffmpeg 比較
TIFF 14 ms 59 ms 🚀 4× 速い
BMP 39 ms 59 ms 🚀 1.5× 速い
GIF 77 ms 65 ms ほぼ同等
PNG 111 ms 60 ms 1.9× 遅い
WebP 207 ms 66 ms 3.1× 遅い
JPEG 304 ms 55 ms 5.5× 遅い

Encode

Format pura-* ffmpeg 比較
TIFF 0.8 ms 58 ms 🚀 73× 速い
BMP 35 ms 58 ms 🚀 1.7× 速い
PNG 52 ms 61 ms 🚀 速い
JPEG 238 ms 62 ms 3.8× 遅い
GIF 377 ms 59 ms 6.4× 遅い

11 操作中 5 つで C 実装より速い結果になりました。これは ffmpeg のプロセス起動オーバーヘッドのほうが処理本体より重いケースがあるためです。JPEG / WebP のような重い圧縮アルゴリズムは Pure Ruby だと不利ですが、サムネイル生成程度であれば実用範囲です。

制限事項・注意点

  • JPEG / WebP のエンコード性能は libvips に劣ります。大量の画像を頻繁に生成するワークロードでは libvips のほうが向いています
  • 大きな画像(数千ピクセル四方)の処理では C 実装との差が広がる可能性があります
  • まだ若いライブラリです。本番投入される際は事前にベンチマーク・E2E テストで検証してください

まとめ

「外部依存を減らして同梱で完結させる」という方向は、Rails 8 の Solid Queue / Solid Cache / Solid Cable などにも通じる流れです。画像処理レイヤでも同じことを Pure Ruby だけで実現したのが pura-image です。

  • gem install で完結
  • Active Storage に config 1 行で統合
  • 7 フォーマット対応、一部処理は C 実装より速い
  • ruby.wasm / JRuby / TruffleRuby でも動く

「Rails の依存をひとつでも減らしたい」「brew install を新人に説明したくない」「Docker イメージを軽くしたい」という方はぜひ試してみてください。GitHub での star や Issue / PR も歓迎です。

リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?