class EM::FastImage
Constants
- DefaultTimeout
- LocalFileChunkSize
Attributes
Public Class Methods
# File lib/em-fastimage.rb, line 163 def initialize(uri, options={}) @property = options[:type_only] ? :type : :size @timeout = options[:timeout] || DefaultTimeout @uri = uri if uri.respond_to?(:read) fetch_using_read(uri) else begin @parsed_uri = Addressable::URI.parse(uri) rescue Addressable::URI::InvalidURIError # fetch_using_open_uri else if @parsed_uri.scheme == "http" || @parsed_uri.scheme == "https" fetch_using_http else # fetch_using_open_uri end end end uri.rewind if uri.respond_to?(:rewind) raise SizeNotFound if options[:raise_on_failure] && @property == :size && !@size rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET, ImageFetchFailure, EOFError, Errno::ENOENT raise ImageFetchFailure if options[:raise_on_failure] rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug raise ImageFetchFailure if options[:raise_on_failure] rescue UnknownImageType raise UnknownImageType if options[:raise_on_failure] rescue CannotParseImage if options[:raise_on_failure] if @property == :size raise SizeNotFound else raise ImageFetchFailure end end end
Returns an array containing the width and height of the image. It will return nil if the image could not be fetched, or if the image type was not recognised.
By default there is a timeout of 2 seconds for opening and reading from a remote server. This can be changed by passing a :timeout => number_of_seconds in the options.
If you wish FastImage
to raise if it cannot size the image for any reason, then pass :raise_on_failure => true in the options.
FastImage
knows about GIF, JPEG, BMP, TIFF, PNG and PSD files.
Example¶ ↑
require 'fastimage' FastImage.size("http://stephensykes.com/images/ss.com_x.gif") => [266, 56] FastImage.size("http://stephensykes.com/images/pngimage") => [16, 16] FastImage.size("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg") => [500, 375] FastImage.size("http://www-ece.rice.edu/~wakin/images/lena512.bmp") => [512, 512] FastImage.size("test/fixtures/test.jpg") => [882, 470] FastImage.size("http://pennysmalls.com/does_not_exist") => nil FastImage.size("http://pennysmalls.com/does_not_exist", :raise_on_failure=>true) => raises FastImage::ImageFetchFailure FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true) => raises FastImage::UnknownImageType FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true, :timeout=>0.01) => raises FastImage::ImageFetchFailure FastImage.size("http://stephensykes.com/images/faulty.jpg", :raise_on_failure=>true) => raises FastImage::SizeNotFound
Supported options¶ ↑
- :timeout
-
Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
- :raise_on_failure
-
If set to true causes an exception to be raised if the image size cannot be found for any reason.
# File lib/em-fastimage.rb, line 116 def self.size(uri, options={}) (o = new(uri, options)).size o end
Returns an symbol indicating the image type fetched from a uri. It will return nil if the image could not be fetched, or if the image type was not recognised.
By default there is a timeout of 2 seconds for opening and reading from a remote server. This can be changed by passing a :timeout => number_of_seconds in the options.
If you wish FastImage
to raise if it cannot find the type of the image for any reason, then pass :raise_on_failure => true in the options.
Example¶ ↑
require 'fastimage' FastImage.type("http://stephensykes.com/images/ss.com_x.gif") => :gif FastImage.type("http://stephensykes.com/images/pngimage") => :png FastImage.type("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg") => :jpeg FastImage.type("http://www-ece.rice.edu/~wakin/images/lena512.bmp") => :bmp FastImage.type("test/fixtures/test.jpg") => :jpeg FastImage.type("http://pennysmalls.com/does_not_exist") => nil File.open("/some/local/file.gif", "r") {|io| FastImage.type(io)} => :gif FastImage.type("test/fixtures/test.tiff") => :tiff FastImage.type("test/fixtures/test.psd") => :psd
Supported options¶ ↑
- :timeout
-
Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
- :raise_on_failure
-
If set to true causes an exception to be raised if the image type cannot be found for any reason.
# File lib/em-fastimage.rb, line 159 def self.type(uri, options={}) new(uri, options.merge(:type_only=>true)).type end
Private Instance Methods
# File lib/em-fastimage.rb, line 208 def fetch_using_http @redirect_count = 0 fetch_using_http_from_parsed_uri end
# File lib/em-fastimage.rb, line 214 def fetch_using_http_from_parsed_uri setup_http @http.get.callback do |res| # begin # newly_parsed_uri = Addressable::URI.parse(res['Location']) # # The new location may be relative - check for that # if newly_parsed_uri.scheme != "http" && newly_parsed_uri.scheme != "https" # @parsed_uri.path = res['Location'] # else # @parsed_uri = newly_parsed_uri # end # rescue Addressable::URI::InvalidURIError # else # fetch_using_http_from_parsed_uri # break # end # read_fiber = Fiber.new do res.response do |str| Fiber.yield str end end succeed(parse_packets FiberStream.new(read_fiber)) end.errback do |err| fail(err) end end
# File lib/em-fastimage.rb, line 292 def fetch_using_open_uri open(@uri) do |s| fetch_using_read(s) end end
# File lib/em-fastimage.rb, line 268 def fetch_using_read(readable) # Pathnames respond to read, but always return the first # chunk of the file unlike an IO (even though the # docuementation for it refers to IO). Need to supply # an offset in this case. if readable.is_a?(Pathname) read_fiber = Fiber.new do offset = 0 while str = readable.read(LocalFileChunkSize, offset) Fiber.yield str offset += LocalFileChunkSize end end else read_fiber = Fiber.new do while str = readable.read(LocalFileChunkSize) Fiber.yield str end end end succeed(parse_packets FiberStream.new(read_fiber)) end
# File lib/em-fastimage.rb, line 298 def parse_packets(stream) @stream = stream begin result = send("parse_#{@property}") if result instance_variable_set("@#{@property}", result) else raise CannotParseImage end rescue FiberError raise CannotParseImage end end
# File lib/em-fastimage.rb, line 313 def parse_size @type = parse_type unless @type send("parse_size_for_#{@type}") end
# File lib/em-fastimage.rb, line 436 def parse_size_for_bmp d = @stream.read(32)[14..28] header = d.unpack("C")[0] result = if header == 40 d[4..-1].unpack('l<l<') else d[4..8].unpack('SS') end # ImageHeight is expressed in pixels. The absolute value is necessary because ImageHeight can be negative [result.first, result.last.abs] end
# File lib/em-fastimage.rb, line 386 def parse_size_for_gif @stream.read(11)[6..10].unpack('SS') end
# File lib/em-fastimage.rb, line 394 def parse_size_for_jpeg loop do @state = case @state when nil @stream.read(2) :started when :started @stream.read_byte == 0xFF ? :sof : :started when :sof case @stream.read_byte when 0xe1 # APP1 skip_chars = @stream.read_int - 2 data = @stream.read(skip_chars) io = StringIO.new(data) if io.read(4) == "Exif" io.read(2) @exif = Exif.new(IOStream.new(io)) rescue nil end :started when 0xe0..0xef :skipframe when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF :readsize when 0xFF :sof else :skipframe end when :skipframe skip_chars = @stream.read_int - 2 @stream.read(skip_chars) :started when :readsize s = @stream.read(3) height = @stream.read_int width = @stream.read_int width, height = height, width if @exif && @exif.rotated? return [width, height] end end end
# File lib/em-fastimage.rb, line 390 def parse_size_for_png @stream.read(25)[16..24].unpack('NN') end
# File lib/em-fastimage.rb, line 520 def parse_size_for_psd @stream.read(26).unpack("x14NN").reverse end
# File lib/em-fastimage.rb, line 511 def parse_size_for_tiff exif = Exif.new(@stream) if exif.rotated? [exif.height, exif.width] else [exif.width, exif.height] end end
# File lib/em-fastimage.rb, line 367 def parse_type case @stream.peek(2) when "BM" :bmp when "GI" :gif when 0xff.chr + 0xd8.chr :jpeg when 0x89.chr + "P" :png when "II", "MM" :tiff when '8B' :psd else raise UnknownImageType end end
# File lib/em-fastimage.rb, line 244 def proxy_uri begin proxy = ENV['http_proxy'] && ENV['http_proxy'] != "" ? Addressable::URI.parse(ENV['http_proxy']) : nil rescue Addressable::URI::InvalidURIError proxy = nil end proxy end
# File lib/em-fastimage.rb, line 253 def setup_http proxy = proxy_uri real_uri = "#{@parsed_uri.host}"# :#{@parsed_uri.inferred_port}" conn_opts = {} if proxy conn_opts[:proxy] = { host: proxy.host, port: proxy.port } end if @parsed_uri.scheme == 'https' conn_opts[:ssl] = {} # I don't know how to put the keys in here end @http = EM::HttpRequest.new(@parsed_uri, conn_opts) end