RameshVel RameshVel - 16 days ago 3
Ruby Question

Rails: Conditional image resizing with Carrierwave

I need to create different versions of uploaded image conditionally. I know Carrierwave supports this feature. But my requirements are a bit tricky.

For each uploaded image I need to create 2 versions and need to scale the original image based on conditions.

Below code will give you better idea what I am trying to do:

version :leftright, :if => :image? do
process :resize_to_fill => [667*2, 778*2] ,:if => :is_retina_resolution?
process :resize_to_fill => [667, 778] ,:if => !:is_retina_resolution?
end

version :updown, :if => :image? do
process :resize_to_fill => [1024*2, 487*2] ,:if => :is_retina_resolution?
process :resize_to_fill => [1024, 487] ,:if => !:is_retina_resolution?


end

#resize the original image
process :resize_to_fill => [1024*2, 768*2] ,:if => :is_retina_resolution?
process :resize_to_fill => [1024, 768] ,:if => !:is_retina_resolution?

def is_retina_resolution?(new_file)
image = MiniMagick::Image.open(new_file.file)
true if image[:height] >= 1536 and image[:width] >= 2048
end


Apparently this is not working. Carrierwave throws this error:

Errno::ENOENT - No such file or directory - #<ActionDispatch::Http::UploadedFile:0xe41d508>


And I tried another variation:

version :leftright, :if => :image? do

if :is_retina_resolution?
process :resize_to_fill => [667*2, 778*2]
else
process :resize_to_fill => [667, 778]

end

end

version :updown, :if => :image? do

if :is_retina_resolution?
process :resize_to_fill => [1024*2, 487*2]

else
process :resize_to_fill => [1024, 487]

end
end

def is_retina_resolution?(new_file)
image = MiniMagick::Image.open(new_file)
true if image[:height] >= 1536 and image[:width] >= 2048
end


This doesn't throw any error. But it always generates the image in
retina size
(1st condition)

So I tried one more variation:

version :leftright, :if => :image? && :is_retina_resolution do
process :resize_to_fill => [667*2, 778*2]
end

version :leftright, :if => :image? && !:is_retina_resolution do
process :resize_to_fill => [667, 778]
end

version :updown, :if => :image? && :is_retina_resolution do
process :resize_to_fill => [1024*2, 487*2]

end

version :updown, :if => :image? && !:is_retina_resolution do
process :resize_to_fill => [1024, 487]
end


This doesnt throw any error and also not created any version.

Can someone help me out?

Update:

Based on the suggestion by @DMKE, I made this changes, now it works fine

version :leftright, :if => :image? do
process :resize_to_fill => [667*2, 778*2] ,:if => :is_retina_resolution?
process :resize_to_fill => [667, 778] ,:if => :is_not_retina_resolution?
end

version :updown, :if => :image? do
process :resize_to_fill => [1024*2, 487*2] ,:if => :is_retina_resolution?
process :resize_to_fill => [1024, 487] ,:if => :is_not_retina_resolution?

end

#resize the original image
process :resize_to_fill => [1024*2, 768*2] ,:if => :image_and_retina?
process :resize_to_fill => [1024, 768] ,:if => :image_and_not_retina?
process :if => :not_image?



def image_and_retina?(img)
is_img = image? img
return false unless is_img
return is_retina_resolution?(img)
end

def image_and_not_retina?(img)
is_img = image? img
return false unless is_img
return !is_retina_resolution?(img)
end
# returns true if image file
def image?(new_file)
self.file.content_type.include? 'image'
end

def not_image?(new_file)
!self.file.content_type.include? 'image'
end

def is_retina_resolution?(new_file)
image = MiniMagick::Image.open(self.file.file)
true if image[:height] >= 1536 and image[:width] >= 2048
end

def is_not_retina_resolution?(new_file)
image = MiniMagick::Image.open(self.file.file)
true if image[:height] < 1536 and image[:width] < 2048
end

Answer

Although not a syntax error, this code has a semantical flaw:

version :updown, :if => :image? && !:is_retina_resolution  do
  # ...
end

Here, :image? && !:is_retina_resolution always evaluates to false (try !:foo in an IRb terminal), thus the :updown version is never created. The same explanation goes for process foo: [sx,sy], if: !:bar?

Since CarrierWave does not support an :unless option (as far as I can tell), the only way to achieve your goal are some method definitions in your CarrierWave::Uploader::Base subclass:

process resize_to_fill: [667*2, 778*2], if: :image_and_retina?
process resize_to_fill: [667, 778],     if: :image_and_not_retina?

def image_and_retina?(img)
  image?(img) && is_retina_resolution(img)
end

def image_and_not_retina?(img)
  image?(img) && !is_retina_resolution(img)
end