🗒️
Rails+ CarrierWave+MiniMagickでPDFの最初のページのサムネイルを作る
概要
表題の通りで、検索すると色々それっぽいのは出てくるのですが恐らくバージョンが古いものの解説なのかどれもダメで、試行錯誤の結果うまく保存できたのでメモを残しときます。
- rails (7.1.1)
- carrierwave (3.0.5)
- mini_magick (4.12.0)
- image_processing (1.12.2)
コード
class FileItemUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
version :thumb do
# ここに`full_filename`を作るとそれがサムネイルのファイル名になります。
# このUploaderは画像とPDF両対応なのでPDFの時だけ拡張子を変更しています。
# `minimagick!`で`convert: :jpg`してるので拡張子変わってくれそうですが
# 残念ながら変わりません。
def full_filename(for_file)
name = super(for_file)
name = name.sub(/\.pdf$/, '.jpg') if for_file.ends_with?('.pdf')
name
end
# このメソッドでPDFの1ページ目を画像に変換しています。
process :pdf_first_page_to_jpg, if: :pdf?
# サムネイルのサイズ
process resize_to_limit: [280, 280]
end
private
def pdf?(new_file)
new_file.content_type == 'application/pdf'
end
def pdf_first_page_to_jpg
# 以前は`manipulate!`を使っていましたが`minimagick!`に変わりました。
# 引数には`ImageProcessing::Builder`がきます。
# `ImageProcessing::Builder`については
# すぐ下にリンクを貼りましたのでそちらを見てください。
minimagick! do |pdf|
pdf
# `append`は`convert`コマンドに渡す引数を渡せます。
# この二つのオプションを指定しないとものによっては背景が真っ黒になります。
.append('-background', 'white')
.append('-alpha', 'remove')
# `loader`の指定は`convert path/to/file.pdf[0] path/to/file.jpg`
# のようなコマンドを生成します。これでページ指定ができるようです。
.loader(page: 0)
.convert('jpg')
end
end
end
昔ながらのmanipurate!
は同じファイル名を想定しているため、そこでコンバートするとうまくいきません。一度透過なしで1ページのみのPDFに変換し、もう一度convert: :jpg
を呼べば可能ですが、ソースを読んでたらminimagick!
の存在を知りこれに落ち着きました。
308行目あたりを見るとファイル名が変わっていた時のためにゴニョゴニョしていますね。
なんか、よく見ると気持ち悪い処理ですね。jpgに変換したものを一度~.pdf
という元のファイル名に戻してCarrierWave::SanitizedFile.move_to
でまた~.jpg
に戻してますね。CarrierWave::SanitizedFileを新しく生成しなおした方が直感的な気もしますが、負荷的な問題かもしれないですね。
Discussion