0
votes

I have the following model:

class ScreenshotUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick
  storage :file
  convert :jpg

  version :thumb do
    process resize_to_fill: [50, 50]
  end

  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  version :print do
    process border: ['black']
    process quality: 80
  end
end

The upload of the image happens via pasting an image from the clipboard via https://github.com/layerssss/paste.js and is saved as a base64 encoded string into a <textarea>, then uploaded using the https://github.com/y9v/carrierwave-base64 gem:

class Finding < ApplicationRecord
  mount_base64_uploader :screenshot, ScreenshotUploader
end

In the HTML form, it looks like this:

upload form

After uploading, the result is the following files:

  • screenshot.png it's a PNG, not a JPG!
  • thumb_screenshot.jpg
  • print_screenshot.jpg

But I need the original file to be also converted to JPG, as I need to save disk space. How can I achieve this?

2

2 Answers

1
votes

You can do it like it written on the carrier wave documentation Just replace system("mogrify -resize '1200\>' #{file.file}") with system("mogrify -format jpg #{file.file}") and then remove original file.

1
votes

Adding to Vasiliy's answer, I came up with the following:

  after :store, :convert_original_to_jpg

  def convert_original_to_jpg(new_file)
    if version_name.nil?
      system("mogrify -format jpg -quality 80  #{file.file}")
      system("unlink #{file.file}") # Remove the old PNG file
      model.update_column mounted_as, "#{mounted_as}.jpg" # The filename in the DB also needs to be manually set to .jpg!
    end
  end

While this works for creating the file, it does not when updating the file, as the new_file parameter then is nil, and thus all images are removed.

I think this is some quirk that has to do with the carrierwave-base64 gem, and I don't have any motivation to dig into this any further. So the proposed solution might not be too useful, but for the sake of documentation I wanted to post it here.

In my special case, I decided to let go of the idea of saving disk space by converting PNG to JPG. Instead, I simply set process quality: 80 to save at least some space on the versions.

For the original PNG (which is saved in lossless state by carrierwave-base64 gem), I simply use the following code to shrink its quality:

  after :store, :optimise_images

  def optimise_images(new_file)
    return if Rails.env.test? # Optimising consumes quite some time, so let's disable it for tests

    if version_name.nil?
      image_optim = ImageOptim.new pngout: false,
                                   svgo: false,
                                   pngcrush: false,
                                   optipng: false,
                                   pngquant: {allow_lossy: true}, # Everything disabled except pngquant, to keep the performance at a good level
                                   advpng: false
      image_optim.optimize_images!(Dir["#{File.dirname(file.file)}/*.png"])
    end
  end