It so happens that in our application we need to find the dimensions of many images that do not reside on our rails application server. I have previously written about how to use the GD library to find image sizes, but this requires fetching the whole file and having it available in the local file system.Fortunately we know all these files are jpegs, and if you check the jpeg documentation you can see that the dimensions of an image are normally contained near the start, which is ideal. We will just fetch enough of the image to get the dimensions, and no more.How can we do that? The get method from Net::HTTP will do the trick – given a block it will yield each packet of data from the remote server as it arrives. And fetching over http makes this method very general – we can size any jpeg from anywhere using this code.Parsing the returned data for the dimensions requires a simple state machine which will break from the http get block once the dimensions are located.So I ended up with a small class to encapsulate the dimension information from the jpeg, JpegDimensions. Here’s how to use it:
jpg_info = JpegDimensions.new("http://somewhere.co.abc/an_image.jpg")jpg_info.height # is the heightjpg_info.width # is the width??
And the best thing is that only a small part of the image will be fetched, saving time and bandwith.Here’s the code
require 'net/http'class JpegDimensions attr_reader :width, :height def initialize(image_path) @uri_split = URI.split(image_path) find_jpeg_size end def find_jpeg_size begin http = Net::HTTP.new(@uri_split, @uri_split) state = 0 http.get(@uri_split) do |str| # this yields strings as each packet arrives str.each_byte do |b| state = case state when 0 b == 0xFF ? 1 : 0 when 1 b >= 0xC0 && b <= 0xC3 ? 2 : 0 when 2 3 when 3 4 when 4 5 when 5 @height = b * 256 6 when 6 @height += b 7 when 7 @width = b * 256 8 when 8 @width += b break end end break if state == 8 # don't need to fetch any more of the image end rescue Exception=>e # I do nothing here, but you can do something more useful with the exception if required end endend