Find jpeg dimensions fast in pure Ruby, no image library needed
Categories rails, ruby | 19 August, 2008 | By Stephen Sykes
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 height
jpg_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[2], @uri_split[3])
state = 0
http.get(@uri_split[5]) 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
end
end
RSS
Cool, this looks useful. Bookmarked for future reference!
I was using above code for one of my project. But it is not working for some cases such as this file (many of the files on this website) http://www2.meritline.com/images/product/large/153-049.jpg
Code at location http://snippets.dzone.com/posts/show/805 is working fine for the above image but it is not designed for http scenario
[...] just released a gem to find image dimensions and type information fast. I have previously done some work in this area, but this is a much more comprehensive solution, and fixes problems with certain [...]