denisov_2023
@denisov_2023 (デニソフ)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

pdfの1ページ目だけを指定してPNG形式への変換を行う

□解決したいこと

rmagicとcarrierwaveを用いて、投稿したpdfをPNGに変換して表示する機能を実装しております。

その際、複数ページのpdfを投稿した際は1ページ目をPNGに変換して表示しようと考えております。

image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick
  include CarrierWave::MiniMagick
 #省略
  version :thumb do
      process :cover
      process resize_to_limit: [1000, 1000]
      process convert: 'png'
  end

  # 1ページ目だけを指定して抜き出す
  def cover
    image = Magick::Image.read(filename)
    image[0]
  end
#省略

以上のようにproessからcoverを呼び出し、1ページ目を指定して抜き出す処理を行おうと考えています。しかし、def cover~endの記述の方法がわからず、処理がうまくいきません。
carrierwave及びrmagicを使用することが初めてですので、ご意見いただきたく投稿いたしました。

以下ターミナルに表示されるエラー

Started POST "/tips" for ::1 at 2021-05-15 18:45:39 +0900
Processing by TipsController#create as HTML
  Parameters: {"authenticity_token"=>"ToPsPsImK/oGmEf6e6zY57nIMovfzD1OSfKnRaVs8uz1awjjXkrp0R1ud27qCDPlFSqrebSuyLo6bgqZ5xGgdw==", "tip"=>{"title"=>"テスト", "name"=>"", "category_id"=>"3", "image"=>#<ActionDispatch::Http::UploadedFile:0x00007fde8d1156c0 @tempfile=#<Tempfile:/var/folders/6_/7bw90k293ydglk72y4jh4vkc0000gn/T/RackMultipart20210515-36097-1q99ybo.pdf>, @original_filename="建築豆知識アプリ.pdf", @content_type="application/pdf", @headers="Content-Disposition: form-data; name=\"tip[image]\"; filename=\"\xE5\xBB\xBA\xE7\xAF\x89\xE8\xB1\x86\xE7\x9F\xA5\xE8\xAD\x98\xE3\x82\xA2\xE3\x83\x95\xE3\x82\x9A\xE3\x83\xAA.pdf\"\r\nContent-Type: application/pdf\r\n">, "description"=>"aa"}, "commit"=>"投稿する"}
  User Load (0.2ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
Completed 500 Internal Server Error in 743ms (ActiveRecord: 12.6ms | Allocations: 21791)



Magick::ImageMagickError (unable to open image '建築豆知識アプリ.pdf': No such file or directory @ error/blob.c/OpenBlob/3537):

実装の際、参考にしたサイトのURL
https://lab.unicast.ne.jp/2013/11/28/railsrmagickcarrierwaveを使ってアップロードしたpdfの表紙からpng画/

試したこと

prosess :coverをコメントアウトし、1ページのみのpdfを投稿したところ、投稿に成功し画像の変換にも成功しました。
参考URLの方の記述は

  def cover
    manipulate! do |frame, index|
      frame if index.zero?
    end
  end

とありますが、当該記述ですとエラーが発生してしまします。
そのため、Magick::Image.read(filename)で引数を指定して変換を試みましたが、
引数の指示が無効なため、エラー内にNo such fileとなっております。

pdfの1ページ目を指定して抜き出す方法についてもあまり参考がなかったものですので、お分かりの方、ご助言いただけないでしょうか。

何卒、ご教示いただきたくお願い申し上げます。

環境

'rails', '~> 6.0.0'
carrierwave (2.2.1)
rmagick (4.2.2)
ruby '2.6.5'

1

1Answer

Comments

  1. @denisov_2023

    Questioner

    ご回答心から感謝いたします。
    結果は変わらずエラーでした。
    readの引数を指定することが難しくてなかなか実現できません。
    以下エラー全文

    ```
    Magick::ImageMagickError in TipsController#create
    unable to open image '#<CarrierWave::SanitizedFile:0x00007ff9eb42ef40>': No such file or directory @ error/blob.c/OpenBlob/3537
    Extracted source (around line #57):
    55
    56
    57
    58
    59
    60

    # 1ページ目だけを指定してPNG形式への変換を行う
    def cover
    image = Magick::Image.read(file)
    image[0]
    end


    Rails.root: /Users/taniguroarata/originalapp/archtips

    Application Trace | Framework Trace | Full Trace
    app/uploaders/image_uploader.rb:57:in `read'
    app/uploaders/image_uploader.rb:57:in `cover'
    app/models/tip_tag.rb:20:in `block in save'
    app/models/tip_tag.rb:19:in `save'
    app/controllers/tips_controller.rb:19:in `create'
    Request
    Parameters:

    {"authenticity_token"=>"4xY4+zMlRbq/wC1PwUoGYyF2ATccndLqScSi3+xb26MinbhdzcGIxMAV6dSVDHKDZCgqZi/QG/tuMHTXRLWQlQ==",
    "tip"=>
    {"title"=>"テスト",
    "name"=>"test",
    "category_id"=>"2",
    "image"=>
    #<ActionDispatch::Http::UploadedFile:0x00007ff9f4f77470
    @content_type="application/pdf",
    @headers=
    "Content-Disposition: form-data; name=\"tip[image]\"; filename=\"\xE5\x90\x8D\xE7\xA7\xB0\xE6\x9C\xAA\xE8\xA8\xAD\xE5\xAE\x9A\xE3\x81\xAE\xE3\x82\xB3\xE3\x83\x92\xE3\x82\x9A\xE3\x83\xBC.pdf\"\r\n" +
    "Content-Type: application/pdf\r\n",
    @original_filename="名称未設定のコピー.pdf",
    @tempfile=#<File:/var/folders/6_/7bw90k293ydglk72y4jh4vkc0000gn/T/RackMultipart20210517-58534-cql8kp.pdf>>,
    "description"=>"tesy\r\n"},
    "commit"=>"投稿する"}
    ```
  2. unable to open image '#<CarrierWave::SanitizedFile:0x00007ff9eb42ef40>' ということは、 read に渡した file が File オブジェクトではないせいで文字列化されたうえファイル名として扱われているようですね。

    image = Magick::Image.read(file.to_file)

    とすれば File オブジェクトを渡せそうです。参考: https://github.com/carrierwaveuploader/carrierwave/blob/d50d80eee95054d4e2567b685c5b82a8128146f7/lib/carrierwave/sanitized_file.rb#L242-L252
  3. @denisov_2023

    Questioner

    早速のご回答ありがとうございます。
    再度、試してみました。
    結果はエラーでしたが、別のエラー内容となったため、一歩進むことができました。
    本当にありがたいです。
    以下、エラー全文

    ```
    ImageProcessing::Error in TipsController#create
    Source format is multi-layer, but destination format is single-layer. If you care only about the first layer, add `.loader(page: 0)` to your pipeline. If you want to process each layer, see https://github.com/janko/image_processing/wiki/Splitting-a-PDF-into-multiple-images or use `.saver(allow_splitting: true)`.
    Extracted source (around line #20):
    18
    19
    20
    21
    22
    23

    def save(tag_list)
    ActiveRecord::Base.transaction do
    @tip.update(title: title, category_id: category_id, description: description, image: image, user_id: user_id)
    @tip.tip_tag_relations.each do |tag|
    tag.delete
    end

    Rails.root: /Users/taniguroarata/originalapp/archtips

    Application Trace | Framework Trace | Full Trace
    app/models/tip_tag.rb:20:in `block in save'
    app/models/tip_tag.rb:19:in `save'
    app/controllers/tips_controller.rb:19:in `create'
    Request
    Parameters:

    {"authenticity_token"=>"fid+TGIVOj5pc2/s+u74F52jeLSZOCmgO9SZNt2v74u/rP7qnPH3QBamq3euqIz32P1T5ap14LEcIE8+dUGkvQ==",
    "tip"=>
    {"title"=>"テスト",
    "name"=>"",
    "category_id"=>"3",
    "image"=>
    #<ActionDispatch::Http::UploadedFile:0x00007ff9d923dec8
    @content_type="application/pdf",
    @headers=
    "Content-Disposition: form-data; name=\"tip[image]\"; filename=\"\xE5\xBB\xBA\xE7\xAF\x89\xE8\xB1\x86\xE7\x9F\xA5\xE8\xAD\x98\xE3\x82\xA2\xE3\x83\x95\xE3\x82\x9A\xE3\x83\xAA.pdf\"\r\n" +
    "Content-Type: application/pdf\r\n",
    @original_filename="建築豆知識アプリ.pdf",
    @tempfile=#<File:/var/folders/6_/7bw90k293ydglk72y4jh4vkc0000gn/T/RackMultipart20210518-58534-pv57va.pdf>>,
    "description"=>"test"},
    "commit"=>"投稿する"}
    ```

    おそらく、pdfが複数のままですので’Source format is multi-layer’とエラーが発せられたと想定しました。そこで、エラー内の
    https://github.com/janko/image_processing/wiki/Splitting-a-PDF-into-multiple-images
    を参考に
    ```
    version :thumb do
    process :cover
    process resize_to_limit: [1000, 1000]
    process convert: 'png'
    end

    # 1ページ目だけを指定してPNG形式への変換を行う
    def cover
    page_count = MiniMagick::Image.new(pdf_path).pages.count

    magick = ImageProcessing::MiniMagick
    .source(pdf_path)
    .convert("png")

    images = page_count.times.map do |page_number|
    magick.loader(page: page_number).call
    end
    images[0]
    end
    ```

    としてみましたが、やはり変わらずエラーでした。
    ()内のパスの指定がうまくいかないということらしいのですが、やっぱりパスの指定方法がわかりませんでした。
    実践した内容のエラー

    ```
    NameError in TipsController#create
    undefined local variable or method `pdf_path' for #<ImageUploader::Uploader70283797986980:0x00007fd885741e30>
    Extracted source (around line #57):
    55
    56
    57
    58
    59
    60

    # 1ページ目だけを指定してPNG形式への変換を行う
    def cover
    page_count = MiniMagick::Image.new(pdf_path).pages.count

    magick = ImageProcessing::MiniMagick
    .source(pdf_path)

    Rails.root: /Users/taniguroarata/originalapp/archtips

    Application Trace | Framework Trace | Full Trace
    app/uploaders/image_uploader.rb:57:in `cover'
    app/models/tip_tag.rb:20:in `block in save'
    app/models/tip_tag.rb:19:in `save'
    app/controllers/tips_controller.rb:19:in `create'
    Request
    Parameters:

    {"authenticity_token"=>"E5zVGp0zPlG7zRzRJn4X5cMRIZcDcsq8pANJa+33RvvSF1W8Y9fzL8QY2EpyOGMFhk8KxjA/A62D959jRRkNzQ==",
    "tip"=>
    {"title"=>"テスト",
    "name"=>"",
    "category_id"=>"2",
    "image"=>
    #<ActionDispatch::Http::UploadedFile:0x00007fd871825018
    @content_type="application/pdf",
    @headers=
    "Content-Disposition: form-data; name=\"tip[image]\"; filename=\"\xE5\xBB\xBA\xE7\xAF\x89\xE8\xB1\x86\xE7\x9F\xA5\xE8\xAD\x98\xE3\x82\xA2\xE3\x83\x95\xE3\x82\x9A\xE3\x83\xAA.pdf\"\r\n" +
    "Content-Type: application/pdf\r\n",
    @original_filename="建築豆知識アプリ.pdf",
    @tempfile=#<File:/var/folders/6_/7bw90k293ydglk72y4jh4vkc0000gn/T/RackMultipart20210518-60930-1n8ig7v.pdf>>,
    "description"=>"test"},
    "commit"=>"投稿する"}
    ```
  4. とすると def cover は不要かもしれません。
  5. @denisov_2023

    Questioner

    @uasiさん、ありがとうございます。
    ご指摘の通り、

    ```
    version :thumb do
    process convert: ['png', 0]
    process resize_to_limit: [1000, 1000]
    end
    ```
    とし、coverを削除したところ、出来ました。
    def coverの中を色々いじって試しましたが、convertの方を変えれば良いというのは考えませんでした。
    これを実現したくて一月近く悩んでおりましたので、本当にありがとうございます。

Your answer might help someone💌