sdsykes-fastimage 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -14,6 +14,8 @@ FastImage does this minimal fetch for image types GIF, JPEG, PNG and BMP. And i
14
14
 
15
15
  You only need supply the uri, and FastImage will do the rest.
16
16
 
17
+ Fastimage can also read local (and other) files, and uses the open-uri library to do so.
18
+
17
19
  h2. Examples
18
20
 
19
21
  <pre>
@@ -24,6 +26,8 @@ FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
24
26
  => [266, 56] # width, height
25
27
  FastImage.type("http://stephensykes.com/images/pngimage")
26
28
  => :png
29
+ FastImage.type("/some/local/file.gif")
30
+ => :gif
27
31
  </code>
28
32
  </pre>
29
33
 
@@ -62,10 +66,10 @@ You'll need to 'sudo gem install fakeweb' to be able to run the tests.
62
66
  ruby test/test.rb
63
67
  Loaded suite test/test
64
68
  Started
65
- .........
66
- Finished in 0.055059 seconds.
69
+ ...............
70
+ Finished in 0.059392 seconds.
67
71
 
68
- 9 tests, 15 assertions, 0 failures, 0 errors
72
+ 15 tests, 27 assertions, 0 failures, 0 errors
69
73
  </code>
70
74
  </pre>
71
75
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 2
2
+ :patch: 0
3
3
  :major: 1
4
- :minor: 0
4
+ :minor: 1
data/lib/fastimage.rb CHANGED
@@ -8,6 +8,11 @@
8
8
  #
9
9
  # FastImage knows about GIF, JPEG, BMP and PNG files.
10
10
  #
11
+ # FastImage can also read files from the local filesystem by supplying the path instead of a uri.
12
+ # In this case FastImage uses the open-uri library to read the file in chunks of 256 bytes until
13
+ # it has enough. This is possibly a useful bandwidth-saving feature if the file is on a network
14
+ # attached disk rather than truly local.
15
+ #
11
16
  # === Examples
12
17
  # require 'fastimage'
13
18
  #
@@ -15,6 +20,8 @@
15
20
  # => [266, 56]
16
21
  # FastImage.type("http://stephensykes.com/images/pngimage")
17
22
  # => :png
23
+ # FastImage.type("/some/local/file.gif")
24
+ # => :gif
18
25
  #
19
26
  # === References
20
27
  # * http://snippets.dzone.com/posts/show/805
@@ -23,6 +30,7 @@
23
30
  # * http://imagesize.rubyforge.org/
24
31
  #
25
32
  require 'net/https'
33
+ require 'open-uri'
26
34
 
27
35
  class FastImage
28
36
  attr_reader :size, :type
@@ -39,11 +47,13 @@ class FastImage
39
47
  end
40
48
 
41
49
  DefaultTimeout = 2
50
+
51
+ LocalFileChunkSize = 256
42
52
 
43
53
  # Returns an array containing the width and height of the image.
44
54
  # It will return nil if the image could not be fetched, or if the image type was not recognised.
45
55
  #
46
- # By default there is a timeout of 2 seconds for opening and reading from the remote server.
56
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
47
57
  # This can be changed by passing a :timeout => number_of_seconds in the options.
48
58
  #
49
59
  # If you wish FastImage to raise if it cannot size the image for any reason, then pass
@@ -63,6 +73,8 @@ class FastImage
63
73
  # => [500, 375]
64
74
  # FastImage.size("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
65
75
  # => [512, 512]
76
+ # FastImage.size("test/fixtures/test.jpg")
77
+ # => [882, 470]
66
78
  # FastImage.size("http://pennysmalls.com/does_not_exist")
67
79
  # => nil
68
80
  # FastImage.size("http://pennysmalls.com/does_not_exist", :raise_on_failure=>true)
@@ -87,7 +99,7 @@ class FastImage
87
99
  # Returns an symbol indicating the image type fetched from a uri.
88
100
  # It will return nil if the image could not be fetched, or if the image type was not recognised.
89
101
  #
90
- # By default there is a timeout of 2 seconds for opening and reading from the remote server.
102
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
91
103
  # This can be changed by passing a :timeout => number_of_seconds in the options.
92
104
  #
93
105
  # If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
@@ -105,6 +117,8 @@ class FastImage
105
117
  # => :jpg
106
118
  # FastImage.type("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
107
119
  # => :bmp
120
+ # FastImage.type("test/fixtures/test.jpg")
121
+ # => :jpg
108
122
  # FastImage.type("http://pennysmalls.com/does_not_exist")
109
123
  # => nil
110
124
  #
@@ -119,52 +133,65 @@ class FastImage
119
133
  end
120
134
 
121
135
  def initialize(uri, options={})
122
- @type_only = options[:type_only]
123
- setup_http(uri, options)
124
- @http.request_get(@http_get_path) do |res|
125
- raise ImageFetchFailure unless res.is_a?(Net::HTTPSuccess)
126
- fetch_size_from_response(res)
136
+ @property = options[:type_only] ? :type : :size
137
+ @timeout = options[:timeout] || DefaultTimeout
138
+ @uri = uri
139
+ @parsed_uri = URI.parse(uri)
140
+ if @parsed_uri.scheme == "http" || @parsed_uri.scheme == "https"
141
+ fetch_using_http
142
+ else
143
+ fetch_using_open_uri
127
144
  end
128
- raise SizeNotFound if options[:raise_on_failure] && !@size
145
+ raise SizeNotFound if options[:raise_on_failure] && !@type_only && !@size
129
146
  rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET, ImageFetchFailure
130
147
  raise ImageFetchFailure if options[:raise_on_failure]
148
+ rescue Errno::ENOENT
149
+ raise ImageFetchFailure if options[:raise_on_failure]
131
150
  rescue UnknownImageType
132
151
  raise UnknownImageType if options[:raise_on_failure]
133
152
  end
134
153
 
135
154
  private
136
155
 
137
- def setup_http(uri, options)
138
- u = URI.parse(uri)
139
- @http = Net::HTTP.new(u.host, u.port)
140
- @http.use_ssl = (u.scheme == "https")
141
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
142
- @http.open_timeout = options[:timeout] || DefaultTimeout
143
- @http.read_timeout = options[:timeout] || DefaultTimeout
144
- @http_get_path = u.request_uri
156
+ def fetch_using_http
157
+ setup_http
158
+ @http.request_get(@parsed_uri.request_uri) do |res|
159
+ raise ImageFetchFailure unless res.is_a?(Net::HTTPSuccess)
160
+ res.read_body do |str|
161
+ break if parse_packet(str)
162
+ end
163
+ end
145
164
  end
146
165
 
147
- def fetch_type_from_response(res)
148
- fetch_from_response(res, :type){parse_type}
166
+ def setup_http
167
+ @http = Net::HTTP.new(@parsed_uri.host, @parsed_uri.port)
168
+ @http.use_ssl = (@parsed_uri.scheme == "https")
169
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
170
+ @http.open_timeout = @timeout
171
+ @http.read_timeout = @timeout
149
172
  end
150
173
 
151
- def fetch_size_from_response(res)
152
- fetch_from_response(res, :size){parse_size}
174
+ def fetch_using_open_uri
175
+ open(@uri) do |s|
176
+ while str = s.read(LocalFileChunkSize)
177
+ break if parse_packet(str)
178
+ end
179
+ end
153
180
  end
154
181
 
155
- def fetch_from_response(res, item)
156
- @unused_str = ""
157
- res.read_body do |str|
158
- @str = @unused_str + str
159
- @strpos = 0
160
- begin
161
- result = yield
162
- if result
163
- instance_variable_set("@#{item}", result)
164
- break
165
- end
166
- rescue MoreCharsNeeded
182
+ # returns true once result is achieved
183
+ #
184
+ def parse_packet(str)
185
+ @str = (@unused_str || "") + str
186
+ @strpos = 0
187
+ begin
188
+ result = send("parse_#{@property}")
189
+ if result
190
+ instance_variable_set("@#{@property}", result)
191
+ true
167
192
  end
193
+ rescue MoreCharsNeeded
194
+ false
168
195
  end
169
196
  end
170
197
 
data/test/test.rb CHANGED
@@ -2,11 +2,13 @@ require 'rubygems'
2
2
 
3
3
  require 'test/unit'
4
4
 
5
- require 'fastimage'
5
+ PathHere = File.dirname(__FILE__)
6
+
7
+ require File.join(PathHere, "..", "lib", 'fastimage')
6
8
 
7
9
  require 'fakeweb'
8
10
 
9
- FixturePath = File.join(File.dirname(__FILE__), "fixtures")
11
+ FixturePath = File.join(PathHere, "fixtures")
10
12
 
11
13
  GoodFixtures = {
12
14
  "test.bmp"=>[:bmp, [40, 27]],
@@ -75,4 +77,34 @@ class FasImageTest < Test::Unit::TestCase
75
77
  FastImage.size(TestUrl + "test.ico", :raise_on_failure=>true)
76
78
  end
77
79
  end
80
+
81
+ def test_should_report_type_correctly_for_local_files
82
+ GoodFixtures.each do |fn, info|
83
+ assert_equal info[0], FastImage.type(File.join(FixturePath, fn))
84
+ end
85
+ end
86
+
87
+ def test_should_report_size_correctly_for_local_files
88
+ GoodFixtures.each do |fn, info|
89
+ assert_equal info[1], FastImage.size(File.join(FixturePath, fn))
90
+ end
91
+ end
92
+
93
+ def test_should_return_nil_on_fetch_failure_for_local_path
94
+ assert_nil FastImage.size("does_not_exist")
95
+ end
96
+
97
+ def test_should_return_nil_for_faulty_jpeg_where_size_cannot_be_found_for_local_file
98
+ assert_nil FastImage.size(File.join(FixturePath, "faulty.jpg"))
99
+ end
100
+
101
+ def test_should_return_nil_when_image_type_not_known_for_local_file
102
+ assert_nil FastImage.size(File.join(FixturePath, "test.ico"))
103
+ end
104
+
105
+ def test_should_raise_when_asked_to_when_size_cannot_be_found_for_local_file
106
+ assert_raises(FastImage::SizeNotFound) do
107
+ FastImage.size(File.join(FixturePath, "faulty.jpg"), :raise_on_failure=>true)
108
+ end
109
+ end
78
110
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sdsykes-fastimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes