TLDR: I forked carrierwave-video-thumbnailer
and added MiniMagick post-processing support.
Using good ol’ Carrierwave to upload video files to S3, I came across a need to generate video thumbnails. A quick Google revealed carrierwave-video-thumbnailer
, which worked perfectly.
However, I needed to rotate the thumbnails (90 degrees clockwise)1 before uploading them. I thought it would be trivial, but it turned out that Carrierwave’s DSL made using multiple processes in a version block intractable.
# original without rotating
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video::Thumbnailer
version :preview_image do
process thumbnail: [{format: 'jpg', quality: 8, size: 360, logger: Rails.logger}]
def full_filename for_file
jpg_name for_file, version_name
end
end
def jpg_name for_file, version_name
%Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.jpg}
end
end
# with rotating, in an ideal world
# sadly, real life doesn't work that way
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
include CarrierWave::Video::Thumbnailer
version :preview_image do
process thumbnail: [{format: 'jpg', quality: 8, size: 360, logger: Rails.logger}]
process :rotate
def full_filename for_file
jpg_name for_file, version_name
end
end
def rotate
manipulate! do |img|
img.rotate "90"
img
end
end
def jpg_name for_file, version_name
%Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.jpg}
end
end
I couldn’t find a reasonable way to proceed from here, and after spending 2-3 hours trying different permutations of the above, wrangling Carrierwave’s DSL and trying to get things to work, I finally dug into the carrierwave-video-thumbnailer
gem to see if I could get MiniMagick to work inside of the process :thumbnail
call.
To expose as much of MiniMagick’s API as possible, I opted for the user to pass in a Proc.
To use it, simply pass in a Proc as mini_magick_opts
:
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video::Thumbnailer
mini_magick_proc = Proc.new { |image|
image.rotate "90" # rotates the image 90 degrees clockwise
}
version :preview_image do
process thumbnail: [{format: 'jpg', quality: 8, size: 360, logger: Rails.logger, mini_magick_opts: mini_magick_proc}]
def full_filename for_file
jpg_name for_file, version_name
end
end
def jpg_name for_file, version_name
%Q{#{version_name}_#{for_file.chomp(File.extname(for_file))}.jpg}
end
end
You can look a look at my commit here for more detail on how I implemented the change.
Footnotes
-
For some reason, the thumbnails that
carrierwave-video-thumbnailer
were generating from portrait iOS videos were rotated 90 degrees counter-clockwise. Some others have faced this issue as well. ↩