I want to compress my images only when the size is greater than 200kb before uploading them to s3 bucket,In my case images are not connected with any model, I am directly uploading it to s3 using storage as aws
My Uploader is
class CoverImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
#include CarrierWave::RMagick
include CarrierWave::MiniMagick
process :compress_image, if: :size_is_large?
# Choose what kind of storage to use for this uploader:
storage :aws
# 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 initialize(location_id)
#location_id = location_id
end
def store!(*args)
super
#file
end
def store_dir
"uploads/cover-images/#{#location_id}"
end
def compress_image
manipulate! do |img|
img.quality("60")
img
end
end
def size_is_large? picture
image = MiniMagick::Image.new(picture.path)
(image[:size]/1000) > 200
end
end
I am using following code to upload the image
image = MiniMagick::Image.open(https://abc.s3.amazon.com/uploads/image.png)
image_type = image.type.downcase
image_name = "#{location}.#{image_type}"
image_path = Rails.root.join("tmp", image_name)
file = File.open(image_path, 'wb') do |output|
output.write RestClient.get(cover_image["url"])
output.path
end
uploader = CoverImageUploader.new("test123")
s3_path = File.open(file) do |file|
uploaded_image = uploader.store!(file)
uploaded_image.url
end
For jpg and jpeg the above code is working fine but in case of png image, instead of decreasing the size its increasing the image size
My file size was 602 kb in png but it got increased to 1.3 mb after uploading it to s3
I want it to be compressed so the image can load faster on our webpages.
Can anyone please suggest what should I do for png image to be compressed ?
Related
so I have a web application that runs fine in development, and with carrierwave and imagemagick I make some changes on the photos that I need to upload. The problem is that when on heroku when i ask for the main version of the photo it still gives me the thumb version
class BannerUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
if Rails.env.development?
storage :file
else
storage :dropbox
end
def store_dir
if version_name.nil?
"uploads/#{model.class.to_s.underscore}/#{mounted_as}"
else
"uploads/#{model.class.to_s.underscore}/#{mounted_as}_#{version_name}"
end
end
process convert: :jpg
process :crop
process resize_to_limit: [1200, 260]
def crop
if model.crop_x.present?
manipulate! do |img|
x = model.crop_x.to_i
y = model.crop_y.to_i
w = model.crop_w.to_i
h = model.crop_h.to_i
r = model.crop_r.to_i
img.rotate r
img.crop([[w, h].join('x'), [x, y].join('+')].join('+'))
end
end
end
version :thumb do
process resize_to_fill: [640, 320]
end
def extension_whitelist
%w(jpg jpeg png)
end
def filename
if original_filename
"#{secure_token}.#{file.extension}"
elsif file
file.filename
end
end
protected
def secure_token
var = :"##{mounted_as}_secure_token"
model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
end
end
this is my uploader
then in my views i have image_tag(model.banner_url(:thumb) to get the thumb version and image_tag #model.banner_url to get the large version. The problem is that the second one on my local machine runs just fine, but when on heroku it gives me the same image of the first one. It does create the right folders and files, and it does crop them right, but it doesn't retrieve the correct one. I am using the
gem 'dropbox-sdk-v2', '~> 0.0.3'
gem 'carrierwave-dropbox', '~> 2.0'
as heroku storage, with obviously a dropbox account
Often you'll want to add different versions of the same file. The
classic example is image thumbnails. There is built in support for
this*
I think the problem is the way you define the store_dir method.
Define it this way:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
And also CarrierWave documentation recommends to use the uploader this way:
uploader = AvatarUploader.new
uploader.store!(my_file) # size: 1024x768
uploader.url # => '/url/to/my_file.png' # size: 800x800
uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
Source: https://github.com/carrierwaveuploader/carrierwave
I'm using carrierwave and mini_magick to resize my images, generate thumbnails. It works great for still images such as jpg and png, but when I try gif, it distorts it. You can see original vs the resized example below. Any idea how I make make it generate gif thumb without breaking it?
Original GIF :) https://imgur.com/oi1f8XT
Generated Thumbnail GIF :( https://imgur.com/a/PwAXv
ps how came the thumbnail's size is bigger than the original? Original is 800*600px and thumbnail is 400*300px. The whole point of generating thumbnail is having smaller file size anyways.
Thank you!
image_uploader.rb
class ImageUploader < 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
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url(*args)
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
def default_url(*args)
ActionController::Base.helpers.asset_path("fallback/" + [version_name, "post.jpg"].compact.join('_'))
end
# Process files as they are uploaded:
# process scale: [800, 600]
# process :resize_to_fit => [800, 600]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process resize_to_fit: [50, 50]
# end
version :thumb do
process resize_to_fit: [400, 300]
end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
def extension_whitelist
%w(jpg jpeg gif png)
end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
The gif you're trying to resize is optimized so that, after the first frame, each subsequent frame contains only the pixels that need to change. When the gif animates, the frames are stacked on top of one another creating the full animation.
Additionally, each frame is only large enough to contain the pixels that need to change. So, the size of each frame is different. When you resize the gif, Imagemagick is resizing each frame to be 400 by 300px regardless of its original size, which is causing the distortion you see.
You can fix this applying an Imagemagick command (with Minimagick bindings in Ruby) called coalesce. It de-optimizes the original image so that each frame is the full size of the canvas.
Calling coalesce makes the file size much larger, so it's necessary to re-optimize the gif once you're done resizing it.
Here's an example:
version :thumb do
process my_resize: [400, 300]
end
def my_resize(width, height)
if #file.content_type == "image/gif"
gif_safe_transform! do |image|
image.resize "#{width}x#{height}" # Perform any transformations here.
end
else
# Process other filetypes if necessary.
end
end
def gif_safe_transform!
MiniMagick::Tool::Convert.new do |image|
image << #file.path
image.coalesce # Remove optimizations so each layer shows the full image.
yield image
image.layers "Optimize" # Re-optimize the image.
image << #file.path
end
end
I wrote a more in-depth explanation with some examples here
I am using Carrierwave to upload images and that works fine but I am now trying to use Minimagick to process these uploaded images.
What is going on?
The images still upload as well as their thumb version, however both images are exactly the same size.
Here is the uploader code:
class FileUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# Override the directory where uploaded files will be stored.
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_fit => [100, 100]
end
# Add a white list of extensions which are allowed to be uploaded.
def extension_white_list
%w(jpg jpeg gif png)
end
end
And here is how I am calling it:
<%= image_tag example.my_file.url(:thumb).to_s %>
I dont think it is anything to do with the way I am calling it because the two files created by all this are the same, so sound slike its to do with processing it on upload.
Here is the folder created for each object:
Image
--- Fixed ---
The issue was ImageMagick. It was not properly configured on my machine so that means no gem that deals with image processing (Paperclip, Minimagick or Dragonfly) could complete any image manipulation.
I am using carrierwave_backgrounder to upload images to S3 in a background process with Sidekiq.
Here's my background_uploader.rb class...
class BackgroundUploader < CarrierWave::Uploader::Base
include ::CarrierWave::Backgrounder::Delay
include CarrierWave::RMagick
include CarrierWave::MimeTypes
process :set_content_type
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
storage :fog
def store_dir
"uploads/backgrounds/#{model.id}"
end
def default_url
"/assets/default.jpg"
end
process :resize_to_fit => [1024, 1024]
process :convert => 'jpg'
process :fix_exif_rotation
def extension_white_list
%w(jpg jpeg png)
end
def filename
#name ||= Digest::MD5.hexdigest(File.dirname(current_path.to_s))
"#{#name}.#{file.extension}" if original_filename
end
# Rotates the image based on the EXIF Orientation & applies gaussian blur
def fix_exif_rotation
manipulate! do |img|
img.auto_orient!
img = yield(img) if block_given?
img = img.gaussian_blur(0.0, 20.0)
img
end
end
end
carrierwave_backgrounder.rb:
CarrierWave::Backgrounder.configure do |c|
c.backend :sidekiq, queue: :carrierwave
end
background.rb contains:
mount_uploader :image, BackgroundUploader
process_in_background :image
I then run sidekiq -q carrierwave to fire up the background workers. All is working good! Upload a file, I see the queue accept it and start working...
If I immediately open up my AWS S3 Console I see the original file in there. Non-resized and un-blurred. Once the job is complete...I refresh S3 and there's the resized/blurred version. Now both images are in there, but I only want the blurred image to be there. In my view I use...
<%= image_tag(#background.image.to_s) %>
It displays the original file. If I check the checkbox to remove the file, it does so as it should (deletes the original from S3), but the blurred version stays there.
What's getting uploaded to S3...
original.jpg (immediate...I don't want this uploaded at all)
modified.jpg (after job completes)
Long story short: I don't want the original file to upload to S3.
I think your problem is the filename method, which carrierwave may rely on to find (and delete) the original file. Does the problem go away when you use a filename that doesn't change between when it's initially stored and when you process it?
I am having trouble implementing a simple image uploader with Carrierwave/Minimagick gems in RoR.
I'm trying to convert the file to grayscale upon upload, but I am getting an error. Here is the code:
image_uploader.rb:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
include Sprockets::Helpers::RailsHelper
include Sprockets::Helpers::IsolatedHelper
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Process files as they are uploaded:
process :convert_to_grayscale
def convert_to_grayscale
manipulate! do |img|
img.quantize(256, Magick::GRAYColorspace)
img = yield(img) if block_given?
img
end
end
When I try to upload a file, I get the following error:
uninitialized constant ImageUploader::Magick
app/uploaders/image_uploader.rb:36:in `block in convert_to_grayscale'
app/uploaders/image_uploader.rb:35:in `convert_to_grayscale'
I believe this is due to the Magick::GRAYColorspace enum constant. Any ideas why this isnt working?
Is the manipulate function that loads images to memory? Does It return a image list?
I think that the images aren't loaded correctly. The problem isn't the Magick enum.
Here is a sample example:
require 'RMagick'
clown = Magick::ImageList.new("clown.jpg")
clown = clown.quantize(256, Magick::GRAYColorspace)
clown.write('monochrome.jpg')