Skip to main content

Generating preview for pdf and images using Carrierwave in Rails


This blog post will cover how to generate the preview of pdf files using Carrierwave gem.

Carrierwave gem has an inbuilt "manipulate!" method which reads the file and loops over every page. This "manipulate!" method works as expected for a pdf having 300-400 pages but when I uploaded a pdf having 1000+ pages my machine crashed!!!
That is when I started debugging the code and found out that there is an issue with the manipulate method.

Here is my original code.

class MyUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  def cover
    manipulate! do |frame, index|
      frame if index.zero? # take only the first page of the file
    end
  end

  version :preview do
    process :cover
    process :resize_to_fit => [310, 438]
    process :convert => :jpg

    def full_filename (for_file = model.source.file)
      super.chomp(File.extname(super)) + '.jpg'
    end
  end

end
source: http://makandracards.com/makandra/20305-howto-provide-a-single-page-preview-for-pdf-txt-with-carrierwave

Above code works only when the number of pages is small but for large number of pages the machine crashes.
The implementation for manipulate! method is shown below.

  def manipulate!(options={}, &block)
    cache_stored_file! if !cached?

          read_block = create_info_block(options[:read])
          image = ::Magick::Image.read(current_path, &read_block)
          frames = ::Magick::ImageList.new

          image.each_with_index do |frame, index|
             frame = yield *[frame, index, options].take(block.arity) if block_given?
             frames << frame if frame
          end 
          frames.append(true) if block_given?

          write_block = create_info_block(options[:write])
          if options[:format] || @format
             frames.write("#{options[:format] || @format}:#{current_path}", &write_block)
          else
             frames.write(current_path, &write_block)
    end 
    destroy_image(frames)
           rescue ::Magick::ImageMagickError => eraise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.rmagick_processing_error", :e => e, :default => I18n.translate(:"errors.messages.rmagick_processing_error", :e => e, :locale => :en))
  end

Notice it will read the whole file each time we need to generate the preview of a single page and there lies our problem.


The solution: USE RMAGICK.

class MyUploader < CarrierWave::Uploader::Base
  include CarrierWave::RMagick

  def convert_to_image(height, width)
    image = ::Magick::Image.read(current_path + "[0]")[0]
    image.resize_to_fit(height,width).write(current_path)
  end

  version :preview do
    process :covert_to_image(100, 100)
    process :convert => :jpg

    def full_filename (for_file = model.source.file)
      super.chomp(File.extname(super)) + '.jpg'
    end
  end

end
In the above code, it will read only the first page of the uploaded pdf and create the preview instead of processing all the pages.
current_path + "[0]" will read the first frame/page of the uploaded pdf.

image = ::Magick::Image.read(current_path + "[0]")[0]
Once we have the first page of pdf then we just need to resize it to the required height and width and save at the desired path.

image.resize_to_fit(height,width).write(current_path)

This solved my problem.

Comments

  1. awesome post presented by you..your writing style is fabulous and keep update with your blogs Ruby on Rails Online Training India

    ReplyDelete

Post a Comment

Popular posts from this blog

Resolve OpenSSL::SSL::SSLError on Yosemite

If you are using rvm installed ruby on Yosemite  OSX  and getting error : OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed then reinstalling ruby with ` --disable-binary` may fix this Issue. rvm reinstall 2.1.2 --disable-binary  Reason: Ruby installed with packaged binary in rvm has OpenSSL path: /etc/openssl  Path of installed openssl is :  /usr/local/etc/openssl To check openssl directory: > irb > require 'openssl' > "SSL_CERT_DIR: %s" % OpenSSL::X509::DEFAULT_CERT_DIR

Letter To Ruby Conf India Organisers

Disclaimer : This article consist of my brutally honest review about Ruby Conf India 2015, If you are prone to depression, heart attack while reading criticism, please STOP reading this letter now  and move on. I know organizers worked hard to organize this event and I thank you for that but this does not mean I am happy with the way it was organised. I have complaints, so do lots of people I know. Someone has to raise voice, for now I am taking this responsibility. 1. Why Discriminate ? I was given accommodation in Justa-panjim while most of the conf attendees were in Cidade-goa, those two hotel are incomparable. Justa-panjim didn't have enough water for bathing, forget about swimming pool, beach. I didn't had complained if everyone was given accommodation in Justa-panjim, Yes I am being jealous here..!!! I paid conf fees(lite tickets.. yes thats how early I booked my ticket.) and I deserve to be treated equally , why discriminate ? 2. Where's Ruby ? In some o