Reputation: 145
I'm processing thumbnail for PDF file in this way:
version :thumb do
process :resize_to_limit => [260, 192]
process :convert => :jpg
process :set_content_type
end
def set_content_type(*args)
self.file.instance_variable_set(:@content_type, "image/jpeg")
end
But when PDF file is multipage it produces thumbnail for all pages in one jpg file. Is there any way to produce thumbnail only for first page?
Upvotes: 12
Views: 6532
Reputation: 2952
The current solution that @tanzeeb came up with is working great for a majority of Image/PDF files and the manipulate function is a useful and dynamic way to manipulate the entire pdf, but it is too broad to be considered a viable method when generating thumbnails, whose main goal is to manipulate only the first page of a pdf.
This manipulate!
code forces the entire file to be read before continuing, and also iterates over that entire file a little later. That's counterintuitive to generating thumbnails and can be a resource problem.
Inside of manipulate
there is a &read_block
that is being passed into ::Magic::Image.read/1
, and that could possibly be used to alter the image data passed into read itself, with one of the read_options
specifying a certain bit of data from the current_path
.
Though, the CarrierWave documentation is too shallow in describing it's possible usages and actually wrong in describing it's code usage. So, this was a dead-end for me.
I wound up sourcing a bunch of code from the manipulate!
function to utilize inside of my own uploader, where I've removed some functionality not used in the generation of the thumbnail.
# @doc Returns the first page of a file
version :thumb, :if => :thumbable? do
process :cover
process convert: "jpg"
def full_filename(filename = model.file.filename) = "#{filename.split(".").first}.jpg"
def style = :thumb
# @doc This is an overridden function from the `manipulate!` function defined in CarrierWaves library
# @doc I removed the ability to pass in options, or a block to the function to use in processing the image.
# @doc This seemed to be the route to go because there isn't many maintainers available on CarrierWave and the documentation is trash.
def cover
cache_file
push_frames(get_frames)
rescue ::Magick::ImageMagickError
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.processing_error")
end
private
# @doc This will store the file available on the uploader in the cache, unless it is already cached.
def cache_file
cache_stored_file! unless cached?
end
# @doc This will utilize RMagick to create an image from an altered current_path variable
# @doc Create a new ImageList, and store the image created as the first frame
def get_frames
path = "#{current_path}[0]"
image = ::Magick::Image.read(path)
frames = ::Magick::ImageList.new
frames << image.first
end
# @doc This will persist the frames created as an ImageList into the file on the uploader, essentially replacing the original pdf with the modified pdf.
def push_frames(frames)
frames.write(current_path)
end
# @doc This will destroy the ImageList that is allocating memory.
def destroy_image(frames)
frames.try(:destroy!)
end
end
Upvotes: 0
Reputation: 3407
Great solution by Tanzeeb! Thank you.
So i could do something like this:
def cover
manipulate! do |frame, index|
frame if index.zero?
end
end
and used this for the thumb generation
version :thumb do
process :cover
process :resize_to_fill => [50, 50, Magick::NorthGravity]
process :convert => 'png'
end
great!
Upvotes: 8
Reputation: 445
I ran across this post when searching for a solution to this same problem. When you convert a pdf to jpeg it creates a long pdf with all the pages attached end to end, so you need to crop the image to the aspect ratio that you want and discard the rest. Below is what I ended up using:
version :thumb_safari do #special version for safari and ios
process :resize_to_fit => [200,200]
process :convert => 'jpg'
process :paper_shape
def full_filename (for_file = model.logo.file)
super.chomp(File.extname(super)) + '.jpg'
end
end
version :thumb do #all browsers except safari
process :resize_to_fit => [200,200]
process :convert => 'jpg' #must convert to jpg before running paper shape
process :paper_shape
process :convert => 'jpg' #after running paper_shape it will default to original file type
def full_filename (for_file = model.logo.file)
super.chomp(File.extname(super)) + '.jpg'
end
end
def paper_shape
manipulate! do |img|
if img.rows*4 != img.columns*3
width=img.columns
height=img.columns/3*4
img.crop!(0,0,width,height,true)
else
img
end
end
end
In the controller/view I used the useragent gem and did this:
documents_controller.rb
def index
@user_agent=UserAgent.parse(request.user_agent)
@search = Document.search(params[:q])
end
index.html.rb
<% if @user_agent.browser.downcase == 'safari' %>
<%= link_to(image_tag(doc.pdfdoc_url(:thumb_safari).to_s, :class=>"dropshadow", :size => "150x225"), doc.pdfdoc_url)%>
<% else %>
<%= link_to(image_tag(doc.pdfdoc_url(:thumb).to_s, :class=>"dropshadow", :size => "150x225"), doc.pdfdoc_url)%>
<% end %>
No doubt there is a better way to do this but this is working for now.
Upvotes: 3
Reputation: 7344
I submitted a patch earlier this year to do just this. Use a custom processor:
def cover
manipulate! do |frame, index|
frame if index.zero?
end
end
process :cover
Upvotes: 15