How can I create thumbnail with carrierwave and a imagemagick script? - ruby-on-rails

I'm using carrierwave to creating thumbnails, but I don't know how can -i use with this script.
mogrify -resize 246x246 -background none -gravity center -extent 246x246 -format png -quality 75 -path thumbs penguins.jpg
This script creating thumbnails and works good, but I would like to use this or similar in carrierwave versions.

The documentation on doing advanced configuration of image manipulation with carrierwave is here:
https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Efficiently-converting-image-formats#full-example
If you look at the def mogrify section, you see that in the img.format("png") do |c| block is where the image manipulation options are passed.
That variable c is actually an instance of MiniMagick, which is a thin wrapper around mogrify.
https://github.com/minimagick/minimagick/
The full API for MiniMagick is not quite there, but if you dig into the source, you can find they have a list of all the possible methods they use here:
https://github.com/minimagick/minimagick/blob/master/lib/mini_magick.rb#L39
And those are all defined down below:
https://github.com/minimagick/minimagick/blob/master/lib/mini_magick.rb#L456
I would suggest adding the options you want to your own uploader:
def mogrify(options = {})
manipulate! do |img|
img.format("png") do |c|
# Add other options here:
c.gravity options[:gravity]
c.background options[:background]
c.extend options[:extend]
c.quality options[:quality]
# Original options follow:
c.fuzz "3%"
c.trim
c.rotate "#{options[:rotate]}" if options.has_key?(:rotate)
c.resize "#{options[:resolution]}>" if options.has_key?(:resolution)
c.resize "#{options[:resolution]}<" if options.has_key?(:resolution)
c.push '+profile'
c.+ "!xmp,*"
c.profile "#{Rails.root}/lib/color_profiles/sRGB_v4_ICC_preference_displayclass.icc"
c.colorspace "sRGB"
end
img
end
end

in your app/uploaders/image_uploader.rb
do something like this
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process :resize_to_limit => [246, 246]
end
end
Take a look at this rails cast 253-carrierwave-file-uploads

Related

why Getting error on uploading the file with Webp-ffi gem?

Unsupported color conversion request
*** WebP::EncoderError Exception: Cannot read input picture file
got this error on certain jpg file. while converting into jpg again from google does the job but why is this?
'''webp_path = "#{filename.ext}.webp"
# Encode (convert) image to webp format with passed options
WebP.encode(path, webp_path, options)
# HACK: Changing of this two instance variables is the only way
# I found to make CarrierWave save new file that was created
# by encoding original image.
#filename = webp_path.split('/').pop
#file = CarrierWave::SanitizedFile.new(
tempfile: webp_path,
filename: webp_path,
content_type: 'image/webp'
)'''
This is what I use successfully, obviously need MiniMagick installed on the dev computer and server:
class ImagesUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"uploads/story/#{model.created_at.strftime('%Y').to_s.underscore}/#{model.created_at.strftime('%m').to_s.underscore}/#{model.created_at.strftime('%d').to_s.underscore}"
end
def default_url(*args)
"/fallback.webp"
end
process :resize_to_fill => [1200, 677]
process convert_to_webp: [{ quality: 80 }]
version :preview do
process convert_to_webp: [{ quality: 80, resize_w: 470, resize_h: 265 }]
end
def extension_allowlist
%w(jpg jpeg gif png webp)
end
private
def convert_to_webp(options = {})
# Build path for new file
webp_path = "#{path}.webp"
# Encode (convert) image to webp format with passed options
WebP.encode(path, webp_path, options)
# HACK: Changing of this two instance variables is the only way
# I found to make CarrierWave save new file that was created
# by encoding original image.
#filename = webp_path.split('/').pop.split('.').first + '.webp'
#file = CarrierWave::SanitizedFile.new(
tempfile: webp_path,
filename: webp_path,
content_type: 'image/webp'
)
end
end

How to open .jpg file with Minimagick?

I have an error with MiniMagick during my "after_upload" in my image_concern.rb
My code makes the image that is poster be converted to jpg. Then it will take the file which is in / tmp and will modify this file to have it also in smaller to display it for later. But I have an error during this step:
`mogrify -resize 360x200^ -gravity Center -crop 360x200+0+0 /tmp/RackMultipart20200211-5215-1lxtqf1.png` failed with error: mogrify: unable to open image '/tmp/RackMultipart20200211-5215-1lxtqf1.png':
It tries to open this file in .png but it is in jpg in my tmp /. How to say that it opens this file but not in png but in jpg. Thank you
This is my after_upload code:
def #{field}_after_upload
path = #{field}_path
options = #{options}
if #{field}_file.respond_to? :path
dir = File.dirname(path)
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
image = MiniMagick::Image.new(#{field}_file.path) do |b|
if options[:resize].ends_with?('!')
b.resize '#{options[:resize].delete('!')}^'
b.gravity 'Center'
b.crop '#{options[:resize].delete('!')}+0+0'
else
b.resize '#{options[:resize].delete('!')}\>'
end
end
image.format 'jpg'
image.write path
if options[:formats]
options[:formats].each do |k, v|
image = MiniMagick::Image.new(#{field}_file.path) do |b|
b.resize "\#{v}^"
b.gravity 'Center'
b.crop "\#{v}+0+0"
end
image.format 'jpg'
image.write path.gsub('.jpg', "_\#{k}.jpg")
end
end
end
end
The bug starts from "if options[:formats]"
Thank you !

RMagick Compression with Cloudinary and Carrierwave

I would like to use the RMagick Compression in Carrierwave before the image is uploaded to Cloudinary.
The local imagemagick tests showed that a 37MB File (Please don't ask why it has that size ;) ) was compressed to only 4,6 MB with an acceptable quality.
So now I would like to use the same functionality in my rails app with rmagick, but it seems like the preprocessing does not take place at all. The uploader uploads the original file with 37MB.
This is what I have at the moment:
class ImageUploader < CarrierWave::Uploader::Base
include Cloudinary::CarrierWave
include CarrierWave::RMagick
process :compress => Magick::JPEGCompression
def compress(compression_type)
manipulate! do |img|
img = img.compression(compression_type)
end
img
end
...
How can I achieve that the compression takes place and only the compressed file is uploaded to cloudinary?
You might want to try our incoming transformation.
For example, you can upload the image using upload widget and add the incoming transformation in the upload preset. or use the SDK. For example:
Cloudinary::Uploader.upload("sample.jpg",
:width => 2000, :height => 1000, :crop => :limit, :quality => 70)

Rails + Carrierwave + RMagick: GIF converts to JPG but doesn't save right file extension

I'm currently trying to get the first frame of a gif file, resize it and save it as a jpg file.
The conversion seems fine I think. But it doesn't save it with the right file extension. It still gets saved as .gif
So when I try to open it it says can't open image, doesn't seem to be a GIF file. Then I rename the extension myself and it works.
Here is my processing code:
version :gif_preview, :if => :is_gif? do
process :remove_animation
process :resize_to_fill => [555, 2000]
process :convert => 'jpg'
end
def remove_animation
manipulate! do |img, index|
index == 0 ? img : nil
end
end
There is actually another, cleaner way to achieve this; and it is even somewhat documented in the official wiki: How To: Move version name to end of filename, instead of front
Using this method your version code would look like this:
version :gif_preview, :if => :is_gif? do
process :remove_animation
process :resize_to_fill => [555, 2000]
process :convert => 'jpg'
def full_filename(for_file)
super.chomp(File.extname(super)) + '.jpg'
end
end
def remove_animation
manipulate! do |img, index|
index == 0 ? img : nil
end
end
So ... I finally found a solution after hours of headaches why this didn't work. Turns out you have to touch/create a file first in order to make this work. I also switched from RMagick to Mini Magick. Not for a particular reason just tried it out if it would work with MiniMagick but I still had the same problem. Here is my new process code with Mini Magick:
version :gif_preview, :if => :is_gif? do
process :gif_to_jpg_convert
end
def gif_to_jpg_convert
image = MiniMagick::Image.open(current_path)
image.collapse! #get first gif frame
image.format "jpg"
File.write("public/#{store_dir}/gif_preview.jpg", "") #"touch" file
image.write "public/#{store_dir}/gif_preview.jpg"
end
I just don't understand why there is really 0 documenation about this ...

Carrierwave RMagick not removing transparency in convert to jpg

I'm trying to upload a PNG and save a bunch of thumbnails. The thumbnails should all be JPG and not have any transparency. Somehow the file is saved as jpg but it has transparency...
Here's my Uploader:
# encoding: utf-8
class WinePhotoUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"assets/wines/#{version_name}"
end
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
# For Rails 3.1+ asset pipeline compatibility:
ActionController::Base.helpers.asset_path("pages/wines/#{version_name}/default.png")
end
process :for_all
process :convert => 'jpg'
version :croppable, :if => :new_upload? do
process :resize_and_pad => [1200, 1200, 'white']
end
version :show, :if => :new_upload? do
process :resize_to_fit => [nil, '425']
end
version :general, :from_version => :show, :if => :new_upload? do
process :resize_and_pad => [150, 375, 'white']
end
version :thumb, :from_version => :croppable, :if => :cropping? do
process :rotate_to => [-30]
process :crop_via_model
process :resize_to_fit => [150, 150]
end
def for_all
manipulate! do |img|
img.trim
img.gravity = Magick::CenterGravity
# I only use these two because this shit isn't working...these don't seem to help!
# Neither does the flatten method...even though other posts on stackoverflow.com say
# that it works.
img.background_color = 'white'
img.alpha Magick::OpaqueAlphaChannel
img.unsharp_mask 0.3, 0.3, 5, 0
img
end
end
def extend_to(w, h)
manipulate! do |img|
img.gravity = Magick::CenterGravity
img.extent w, h
img
end
end
def rotate_to(deg)
manipulate! do |img|
img.gravity = Magick::CenterGravity
img.distort Magick::ScaleRotateTranslateDistortion, deg
#img.repage # WTF?!?!?!? No repage method?!
img
end
end
def crop_via_model
manipulate! do |img|
img.gravity = Magick::CenterGravity
img.crop model.crop_x.to_i, model.crop_y.to_i, model.crop_w.to_i, model.crop_h.to_i
img
end
end
def flatten
manipulate! do |img|
img_list = Magick::ImageList.new
img_list.from_blob img.to_blob
img_list.new_image(img_list.first.columns, img_list.first.rows) { self.background_color = "white" } # Create new "layer" with white background and size of original image
img = img_list.reverse.flatten_images
img
end
end
def new_upload? picture
!model.cropping?
end
def cropping? picture
model.cropping?
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_white_list
%w(jpg jpeg gif png tif)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
def filename
"#{ model.get_permalink(:normalized => true) }.jpg"
end
# Remove this when https://github.com/carrierwaveuploader/carrierwave/issues/1164 is solved.
def recreate_versions!(*versions)
if versions.any?
from_versions = versions.group_by { |v| self.class.versions[v][:options][:from_version] }
from_versions.each do |from, versions|
next if from.nil?
file = CarrierWave::SanitizedFile.new(self.versions[from.to_sym].file)
store_versions!(file, versions)
end
else
super(*versions)
end
end
end
Oh...and apparently carrierwave doesn't seem to want to log anything so I can't tell what it's doing.
There appears to be a quirk with imagemagick and order of operations when converting file types.
Full github issue can be found here: https://github.com/carrierwaveuploader/carrierwave/issues/133#issuecomment-615254
Basically manipulate is called once for every process you have. manipulate opens the current file path, makes changes then writes. Because of this it seems that any process lines that are called after the format conversion are performed on the original file, not the newly converted one.
In order to fix this, you either have to do all of your process operations within a single manipulate block or make sure that the conversion is the last process to run.
The example of this from the github issue is:
process :convert_and_scale
def convert_and_scale
manipulate! do |img|
img.format 'png'
img.resize '100x32'
img
end
end

Resources