We are using carrierwave gem to upload our images on a rails project.
We need to support the creation of the object without an image, but the application will run on several platforms and we don't want to support objects without images in everyone o that platforms, so we want to have a default image.
So this was the first solution
class IconUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"uploads/#{model.id}"
end
def default_url
"/images/icons/" + [version_name, "default.png"].compact.join('_')
end
version :thumbnail do
process resize_to_fill: [200, 200]
end
version :high_resolution do
process resize_to_fill: [400, 400]
end
end
The problem with this is that all the devices will come to the server (not to S3) looking for that default image.
At the same time its a problem with the multiple versions of the image.
So this second solution came:
class CategoryController < ApplicationController
...
def create
#category = Category.new(category_params)
#uploader = IconUploader.new(#category, :icon)
uploader.cache!(File.open("app/assets/images/photos/picture.jpg"))
#category.image=#uploader
#object.save
end
...
end
This solves the problem of the multiple resolutions and it always goes to S3 to get the image. But the problem here is that it will duplicate the default image on S3 many times.
Our third solution could be a to use an already created image on Amazon as default URL, but it has the same problem with the version so we don't even implement it.
Can any one think of a better solution for this problem?
Related
I want to create the ability for the user to upload an image into a pdf which will be generated inside of the app. To do so I'm using gem prawn to pdf creation and CarrierWave::MiniMagic to create thumbnail versions of images for a Rails 6 app, and I've noticed loss of quality when the images are downsized.
original image:
the same image inside of pdf:
Such a bad quality is not acceptable for me. I don't know if it's a common problem but I've found a few posts without any resolution, is there any alternative solution/tool to handle it? I have been struggling with this problem for weeks.
I don't have nothing special in my uploader file:
class LogoUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
EXTENSION_WHITELIST = %w[jpg jpeg png].freeze
storage :file
process convert: 'png'
version :thumb do
process resize_to_fit: [300, 300]
end
def extension_whitelist
EXTENSION_WHITELIST
end
end
I have been struggling to find any tutorial or question that explains how to upload image and resize it according to certain conditions provided by user.
I am easily able to upload and resize image using hard coded values, however I am stuck at using user provided parameters to be accessed from the Uploader.
I want the image to be resized to either 800x600 or 300x300 based on whether the user checks the image as Large or Small.
For that I have a boolean column named "large" in the model structure.
In the Uploader I am able to access model and its values easily in the store_dir block, but anywhere outside this block any model attribute returns as nil.
This is what I want to do:-
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
resize_to_fit(800,600) if model.large==true
resize_to_fit(300,300) if model.large!=true
end
However this returns the error
undefined local variable or method `model' for BannerUploader:Class
How to go about this issue.
To process an original file you can specify custom method:
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
process :process_original_version
def process_original_version
if model.large
resize_to_fit(800,600)
else
resize_to_fit(300,300)
end
end
end
For a specific version:
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :normal do
if model.large
process resize_to_fit: [800,600]
else
process resize_to_fit: [300,300]
end
end
end
Ok so #Alex Kojin has the right answer. However I was faced with another problem as well. When the user submitted the form, the image would be resized always as small (300x300) because for some reason the image resize process would be executed first and then the "large" attribute would be set as true. Therefore the Uploader would always get model.large as false.
So this is how I had to change my action controller
def create
#banner=Banner.new
#banner.large=params[:large]
#banner.update_attributes(banner_params)
#banner.save
redirect_to :back
end
Not sure if this is the right approach but does work for me.
i have a question/problem - im not sure actually, maybe this is how it should behave(?)
I'm using Rails 4 with carrierwave to upload files, I just added the minimagick gem to create versions of the uploaded images.
when i upload image - it works great and make the version.
but when i load a page with images it seems to call the "version" method for every image that is displayed in the screen.... (and its not the upload process! only showing images!)
So even before i uploaded an image and actually created a version of it -> i've added a 'version' method to my uploader file -> refreshed a page in my site -> 'version' method was called (didnt upload anything yet)
my uploader file:
class PhotoUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :fog
version :nav_thumb, if: :is_avatar? do
process :resize_to_fit => [50, 50]
end
version :box_thumb, if: :is_logo? do
process :resize_to_fit => [40, 40]
end
def is_avatar?(picture)
mounted_as == :avatar
end
def is_logo?(picture)
mounted_as == :logo
end
end
it seems that every image displayed in my page is getting to the is_avatar? method (i used pry debugger to see whats going on)
and -> it makes my page load slower, which is the opposite of what i wanted to achieve with smaller image versions.
is this normal behaviour? should it go to the version methods every time i load an image?
what should i do to fix it?
thanks.
I think the issue results from stuffing the logic inside your version methods. Instead of writing if statements inside them, try changing them to these:
version :nav_thumb do
process resize_to_fit: [50,50]
end
version :box_thumb do
process resize_to_fit: [40,40]
end
and then write an additional method to determine which image version should be used (and then implement the result in your view with image_tag image.image_url(:version)).
Try putting your is_*? methods in a protected block:
...
version :nav_thumb, if: :is_avatar? do
process :resize_to_fit => [50, 50]
end
protected
def is_avatar?(picture)
mounted_as.eql?(:avatar)
end
I have an Event model that has many photographs. I have an image uploader mounted to the Photographs attribute, and regular uploads and everything is working fine.
However, when I try and duplicate an event, recreating a new photograph object for the new event, the new image is darker than the original, and if I duplicate the duplicate event, it gets darker still.
I have played around with it, but have no solution.
My Uploader code:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
include CarrierWave::Processing::RMagick
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def cache_dir
"#{Rails.root}/tmp/carrierwave"
end
process :colorspace => :rgb
# Remove EXIF data
process :strip
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_limit => [640, 640]
end
version :preview_thumb do
process :resize_to_limit => [600, 600]
end
version :wine_thumb do
process :resize_to_limit => [160, 440]
end
version :logo_thumb do
process :resize_to_limit => [90, 90]
end
end
And my duplcation code (in Active Admin):
member_action :create_duplicate_event, method: :post do
old_event = Event.find(params[:id])
photograph_urls = old_event.photographs.map(&:image_url)
attributes = old_event.attributes.except("photographs", "id")
new_photos = []
photograph_urls.each do |photo|
new_photo = Photograph.new({
remote_image_url: photo
})
if new_photo.save
new_photos << new_photo
end
end
#event = Event.new(attributes)
#event.photograph_ids = new_photos.map(&:id)
render "/admin/events/_events_form/"
end
The :rgb tag was an attempt to fix. But no luck.
Ruby 2.1 and Rails 4.0
Ok, after a lot of playing around and searching I managed to fix this problem.
First, you need to download the .icc color profiles, which can be found here. It says for windows but they seemed to work for me on my Mac.
Once you have put the .icc files into a /lib/color_profiles directory, add the following code to your uploader:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
process :convert_image_from_cmyk_to_rgb
#versions, and any other uploader code go here
def convert_image_from_cmyk_to_rgb
manipulate! do |image|
if image.colorspace == Magick::CMYKColorspace
image.strip!
image.add_profile("#{Rails.root}/lib/USWebCoatedSWOP.icc")
image.colorspace == Magick::SRGBColorspace
image.add_profile("#{Rails.root}/lib/sRGB.icc")
end
image
end
end
end
This converts CMYK images to RGB, and keeps the profiles keeping nice, while keeping RGB images as they were, and not ruining them.
I hope this helps someone in the future, and saves them the hours I spent working this out.
In my Rails app I would like to allow users to upload either image or non-image files via Carrierwave. Currently Carrierwave is working fine handeling and processing image files, but unfortunately its dropping non-images files completely. Is there a clean way for a single Carrierwave uploader to process both image and non-image files?
I'll include my current uploader below:
class AssetUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process :resize_to_fill => [300, 300]
end
version :icon do
process :resize_to_fill => [48, 48]
end
def extension_white_list
%w(jpg jpeg gif png pdf doc xls docx xlsx ppt)
end
end
I had this exact problem. I solved it with the hoary comp sci solution of one-more-level-of-indirection: a trampoline/thunk method that dynamically decides whether to process based on file extension.
You can find the implementation here: https://gist.github.com/995663
(the naive approach of introducing logic in the version block actually doesn't work because of how the CarrierWave DSL works - the logic needs to be deferred until invocation)
I hope that helps.
I know this has been answered, but aaron's answer doesn't completely solve the problem. You can use what he suggested at https://gist.github.com/995663 if you only need to call process, but not if you want to selectively process with version.
For version, see the carrierwave wiki page here: https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Do-conditional-processing
You can now do this in your code, and it will only process the version block on images
version :thumb, :if => :image? do
process ...
end
protected
def image?(new_file)
new_file.content_type.include? 'image'
end