Как конвертировать PDF в массив изображений с помощью Carrierwave и MiniMagick (Ruby on Rails)

Я конвертирую загруженные PDF-файлы в изображения, по одному изображению на страницу. Я понял, как генерировать изображения, используя MiniMagick::Tool::Convert, но я не знаю, как написать version блок для Uploader, чтобы я мог получить доступ к массиву URL-адресов изображений.

Вот мой загрузчик:

class DocumentUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  storage :file
  # storage :fog

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  version :jpg do
    process :convert_to_images
    process :set_content_type_jpg

    def convert_to_images(*args)
      image = MiniMagick::Image.open(current_path)
      image.pages.each_with_index do |page, index|
        MiniMagick::Tool::Convert.new do |convert|
          convert.background 'white'
          convert.flatten
          convert.density 300
          convert.quality 95
          convert << page.path
          convert << "#{CarrierWave.root}/#{store_dir}/image-#{index}.jpg"
        end
      end
    end
  end

  def set_content_type_jpg(*args)
    self.file.instance_variable_set(:@content_type, "image/jpg")
  end

  # Add a white list of extensions which are allowed to be uploaded.
  def extension_white_list
    %w(jpg jpeg gif png doc docx pdf)
  end
end

Это генерирует image-0.jpg, image-1.jpgи т. д. в правильном каталоге. Но теперь у меня нет возможности ссылаться на эти изображения в моих представлениях или даже знать, сколько их. Это также не будет работать, когда мне нужно загрузить изображения на S3. Как я могу заставить Carrierwave обрабатывать хранилище файлов для этой коллекции изображений вместо одного изображения?

Похоже, мне, вероятно, потребуется добавить новый столбец базы данных для хранения количества страниц. Есть ли способ заставить мой загрузчик возвращать массив URL изображений, основываясь на этом количестве?

Я также готов переключиться на другой драгоценный камень. Разве это будет проще с Paperclip, Shrine или Refile?

1 ответ

Решение

С помощью Shrine вы можете сделать каждую страницу другой версией:

class ImageUploader < Shrine
  plugin :versions
  plugin :processing

  process(:store) do |io, context|
    pdf      = io.download
    versions = {}

    image = MiniMagick::Image.new(pdf.path)
    image.pages.each_with_index do |page, index|
      page_image = Tempfile.new("version-#{index}", binmode: true)
      MiniMagick::Tool::Convert.new do |convert|
        convert.background 'white'
        convert.flatten
        convert.density 300
        convert.quality 95
        convert << page.path
        convert << page_image.path
      end
      page_image.open # refresh updated file
      versions[:"page_#{index + 1}"] = page_image
    end

    versions
  end
end

Если у вас есть Document модель, и вы приложили PDF к file поле вложения, вы можете получить массив страниц, используя Hash#values:

pages = document.file.values
pages #=> [...array of pages...]
pages.count #=> number of pages
Другие вопросы по тегам