4
votes

In my Rails 4 application I have large number of images stored on S3 using Paperclip. Image url looks like http://s3.amazonaws.com/bucketname/files/images/000/000/012/small/image.jpg?1366900621.

Given following attachment class:

  1. How can I download images from S3 and store locally ?
  2. Then how to resize that locally stored image
  3. Upload resized image to another S3 bucket without Paperclip (at a path s3/newbucket/images/{:id}/{imagesize.jpg})

Attachment class:

class Image < ActiveRecord::Base
  has_attached_file :file, styles: { thumbnail: '320x320', icon: '64x64', original: '1080x1080' }
  validates_attachment :file, presence: true, content_type: { content_type: /\Aimage\/.*\Z/ }
end
1

1 Answers

2
votes

The basic advice would be not to resize images on-the-fly as this may take a while and your users may experience a huge response times during this operation. In case you have some predefined set of styles it would be wise to generate them in advance and just return back when required.

Well, here is what you could do if there is no other option.

def download_from_s3 url_to_s3, filename
  uri = URI(url_to_s3)
  response = Net::HTTP.get_response(uri)
  File.open(filename, 'wb'){|f| f.write(response.body)}
end

Here we basically downloaded an image located at a given URL and saved it as a file locally. Resizing may be done in a couple of different ways (it depends on whether you want to serve the downloaded file as a Paperclip attachment). The most common approach here would be to use image-magick and its convert command-line script. Here is an example of resizing an image to width of 30:

convert  -strip -geometry 30 -quality 100 -sharpen 1 '/photos/aws_images/000/000/015/original/index.jpg' '/photos/aws_images/000/000/015/original/S_30_WIDTH__q_100__index.jpg' 2>&1 > /dev/null

You can find documentation for convert here, it's suitable not only for image resizing, but also for converting between image formats, bluring, cropping and much more! Also you could be intrested in Attachment-on-the-Fly gem, which seems a little bit outdated, but has some insights of how to resize images using convert.

The last step is to upload resized image to some S3 bucket. I assume that you've already got aws-sdk gem and AWS::S3 instance (the docs can be found here).

def upload_to_s3 bucket_name, key, file
  s3 = AWS::S3.new(:access_key_id => 'YOUR_ACCESS_KEY_ID', :secret_access_key => 'YOUR_SECRET_ACCESS_KEY')
  bucket = s3.buckets[bucket_name]
  obj = bucket.objects[key]
  obj.write(File.open(file, 'rb'), :acl => :public_read)
end

So, here you obtain an AWS::S3 object to communicate with S3 server, provide your bucket name and desired key, and basically upload an image with an option to make it visible to everybody on the web. Note that there are lots of additional upload options (including file encryption, access permissions, metadata and much more).