fastimage 2.1.3 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/README.textile +1 -1
  3. data/lib/fastimage.rb +138 -12
  4. metadata +15 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e956eb7172b275c005a02bed97037ab008774579
4
- data.tar.gz: cccc887b76405eed9d65e239cad4325eaf4dc437
2
+ SHA256:
3
+ metadata.gz: 53c0966ef5216c189e2950b1ad36c106777175f0d4dca9851abd34472fd9cb61
4
+ data.tar.gz: 29f5a6bc03623e184166e7f9c5e8c4379011b301904d4c690037d5b7b0ba0b33
5
5
  SHA512:
6
- metadata.gz: bf104614fb388b78077820a31b50c713a9a1c6579489758e7331f0247354e9347e27db7f672af36982d0faba4c4e4f44731583f4ae4d6d1eae8ec55657c6feaf
7
- data.tar.gz: 0d14f8f2ae9c597034ecc146f01884e33c3101ff2575679ac101bb3964c8af29f700dec14c4988955bde3600e6afb661a2ac8b62a633905cbb13175c19697035
6
+ metadata.gz: 28e8ec4debe6c2c477da19cafb1ad41e5de4d809136bd86621ae128372c32c1259abea833856f73dfcfe8ef3444bc5e1a148f91b52ee02d3292235c4d95fc542
7
+ data.tar.gz: ba8b4c6bb42146387b1a8af718fbbaf74a9a94532ee5adce082ff676095dad5d5e0eb613f1ec41d7729709847195fa81c4614f2d9d510d6c7def67f8970f168e
@@ -1,5 +1,5 @@
1
1
  !https://img.shields.io/gem/dt/fastimage.svg!:https://rubygems.org/gems/fastimage
2
- !https://travis-ci.org/sdsykes/fastimage.png?branch=master!:https://travis-ci.org/sdsykes/fastimage
2
+ !https://travis-ci.org/sdsykes/fastimage.svg?branch=master!:https://travis-ci.org/sdsykes/fastimage
3
3
 
4
4
  h1. FastImage
5
5
 
@@ -70,7 +70,7 @@ if RUBY_VERSION < "2.2"
70
70
  end
71
71
 
72
72
  class FastImage
73
- attr_reader :size, :type, :content_length, :orientation
73
+ attr_reader :size, :type, :content_length, :orientation, :animated
74
74
 
75
75
  attr_reader :bytes_read
76
76
 
@@ -179,6 +179,34 @@ class FastImage
179
179
  new(uri, options.merge(:type_only=>true)).type
180
180
  end
181
181
 
182
+ # Returns a boolean value indicating the image is animated.
183
+ # It will return nil if the image could not be fetched, or if the image type was not recognised.
184
+ #
185
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
186
+ # This can be changed by passing a :timeout => number_of_seconds in the options.
187
+ #
188
+ # If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
189
+ # :raise_on_failure => true in the options.
190
+ #
191
+ # === Example
192
+ #
193
+ # require 'fastimage'
194
+ #
195
+ # FastImage.animated?("test/fixtures/test.gif")
196
+ # => false
197
+ # FastImage.animated?("test/fixtures/animated.gif")
198
+ # => true
199
+ #
200
+ # === Supported options
201
+ # [:timeout]
202
+ # Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
203
+ # [:raise_on_failure]
204
+ # If set to true causes an exception to be raised if the image type cannot be found for any reason.
205
+ #
206
+ def self.animated?(uri, options={})
207
+ new(uri, options.merge(:animated_only=>true)).animated
208
+ end
209
+
182
210
  def initialize(uri, options={})
183
211
  @uri = uri
184
212
  @options = {
@@ -189,7 +217,13 @@ class FastImage
189
217
  :http_header => {}
190
218
  }.merge(options)
191
219
 
192
- @property = @options[:type_only] ? :type : :size
220
+ @property = if @options[:animated_only]
221
+ :animated
222
+ elsif @options[:type_only]
223
+ :type
224
+ else
225
+ :size
226
+ end
193
227
 
194
228
  @type, @state = nil
195
229
 
@@ -214,7 +248,8 @@ class FastImage
214
248
  raise SizeNotFound if @options[:raise_on_failure] && @property == :size && !@size
215
249
 
216
250
  rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET,
217
- ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT, OpenSSL::SSL::SSLError
251
+ Errno::ENETUNREACH, ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT,
252
+ OpenSSL::SSL::SSLError
218
253
  raise ImageFetchFailure if @options[:raise_on_failure]
219
254
  rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
220
255
  raise ImageFetchFailure if @options[:raise_on_failure]
@@ -242,6 +277,17 @@ class FastImage
242
277
  fetch_using_http_from_parsed_uri
243
278
  end
244
279
 
280
+ # Some invalid locations need escaping
281
+ def escaped_location(location)
282
+ begin
283
+ URI(location)
284
+ rescue URI::InvalidURIError
285
+ ::URI::DEFAULT_PARSER.escape(location)
286
+ else
287
+ location
288
+ end
289
+ end
290
+
245
291
  def fetch_using_http_from_parsed_uri
246
292
  http_header = {'Accept-Encoding' => 'identity'}.merge(@options[:http_header])
247
293
 
@@ -250,7 +296,10 @@ class FastImage
250
296
  if res.is_a?(Net::HTTPRedirection) && @redirect_count < 4
251
297
  @redirect_count += 1
252
298
  begin
253
- @parsed_uri = URI.join(@parsed_uri, URI.escape(res['Location']))
299
+ location = res['Location']
300
+ raise ImageFetchFailure if location.nil? || location.empty?
301
+
302
+ @parsed_uri = URI.join(@parsed_uri, escaped_location(location))
254
303
  rescue URI::InvalidURIError
255
304
  else
256
305
  fetch_using_http_from_parsed_uri
@@ -310,7 +359,7 @@ class FastImage
310
359
  proxy = proxy_uri
311
360
 
312
361
  if proxy
313
- @http = Net::HTTP::Proxy(proxy.host, proxy.port).new(@parsed_uri.host, @parsed_uri.port)
362
+ @http = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new(@parsed_uri.host, @parsed_uri.port)
314
363
  else
315
364
  @http = Net::HTTP.new(@parsed_uri.host, @parsed_uri.port)
316
365
  end
@@ -321,6 +370,7 @@ class FastImage
321
370
  end
322
371
 
323
372
  def fetch_using_read(readable)
373
+ readable.rewind if readable.respond_to?(:rewind)
324
374
  # Pathnames respond to read, but always return the first
325
375
  # chunk of the file unlike an IO (even though the
326
376
  # docuementation for it refers to IO). Need to supply
@@ -356,7 +406,7 @@ class FastImage
356
406
 
357
407
  begin
358
408
  result = send("parse_#{@property}")
359
- if result
409
+ if result != nil
360
410
  # extract exif orientation if it was found
361
411
  if @property == :size && result.size == 3
362
412
  @orientation = result.pop
@@ -378,6 +428,11 @@ class FastImage
378
428
  send("parse_size_for_#{@type}")
379
429
  end
380
430
 
431
+ def parse_animated
432
+ @type = parse_type unless @type
433
+ @type == :gif ? send("parse_animated_for_#{@type}") : nil
434
+ end
435
+
381
436
  def fetch_using_base64(uri)
382
437
  data = uri.split(',')[1]
383
438
  decoded = Base64.decode64(data)
@@ -472,7 +527,12 @@ class FastImage
472
527
  when 0x89.chr + "P"
473
528
  :png
474
529
  when "II", "MM"
475
- :tiff
530
+ case @stream.peek(11)[8..10]
531
+ when "APC", "CR\002"
532
+ nil # do not recognise CRW or CR2 as tiff
533
+ else
534
+ :tiff
535
+ end
476
536
  when '8B'
477
537
  :psd
478
538
  when "\0\0"
@@ -484,7 +544,7 @@ class FastImage
484
544
  when "RI"
485
545
  :webp if @stream.peek(12)[8..11] == "WEBP"
486
546
  when "<s"
487
- :svg
547
+ :svg if @stream.peek(4) == "<svg"
488
548
  when /<[?!]/
489
549
  # Peek 10 more chars each time, and if end of file is reached just raise
490
550
  # unknown. We assume the <svg tag cannot be within 10 chars of the end of
@@ -506,8 +566,69 @@ class FastImage
506
566
  end
507
567
  alias_method :parse_size_for_cur, :parse_size_for_ico
508
568
 
569
+ class Gif # :nodoc:
570
+ def initialize(stream)
571
+ @stream = stream
572
+ end
573
+
574
+ def width_and_height
575
+ @stream.read(11)[6..10].unpack('SS')
576
+ end
577
+
578
+ # Checks if a delay between frames exists and if it does, then the GIFs is
579
+ # animated
580
+ def animated?
581
+ delay = 0
582
+
583
+ @stream.read(10) # "GIF" + version (3) + width (2) + height (2)
584
+
585
+ fields = @stream.read(3).unpack("C")[0] # fields (1) + bg color (1) + pixel ratio (1)
586
+
587
+ # Skip Global Color Table if it exists
588
+ if fields & 0x80
589
+ # 2 * (depth + 1) colors, each occupying 3 bytes (RGB)
590
+ @stream.skip(3 * 2 ** ((fields & 0x7) + 1))
591
+ end
592
+
593
+ loop do
594
+ block_type = @stream.read(1).unpack("C")[0]
595
+ if block_type == 0x21
596
+ extension_type = @stream.read(1).unpack("C")[0]
597
+ size = @stream.read(1).unpack("C")[0]
598
+ if extension_type == 0xF9
599
+ delay = @stream.read(4).unpack("CSC")[1] # fields (1) + delay (2) + transparent index (1)
600
+ break
601
+ elsif extension_type == 0xFF
602
+ @stream.skip(size) # application ID (8) + version (3)
603
+ else
604
+ return # unrecognized extension
605
+ end
606
+ skip_sub_blocks
607
+ else
608
+ return # unrecognized block
609
+ end
610
+ end
611
+
612
+ delay > 0
613
+ end
614
+
615
+ private
616
+
617
+ def skip_sub_blocks
618
+ loop do
619
+ size = @stream.read(1).unpack("C")[0]
620
+ if size == 0
621
+ break
622
+ else
623
+ @stream.skip(size)
624
+ end
625
+ end
626
+ end
627
+ end
628
+
509
629
  def parse_size_for_gif
510
- @stream.read(11)[6..10].unpack('SS')
630
+ gif = Gif.new(@stream)
631
+ gif.width_and_height
511
632
  end
512
633
 
513
634
  def parse_size_for_png
@@ -562,10 +683,10 @@ class FastImage
562
683
  d = @stream.read(32)[14..28]
563
684
  header = d.unpack("C")[0]
564
685
 
565
- result = if header == 40
566
- d[4..-1].unpack('l<l<')
567
- else
686
+ result = if header == 12
568
687
  d[4..8].unpack('SS')
688
+ else
689
+ d[4..-1].unpack('l<l<')
569
690
  end
570
691
 
571
692
  # ImageHeight is expressed in pixels. The absolute value is necessary because ImageHeight can be negative
@@ -767,4 +888,9 @@ class FastImage
767
888
  svg = Svg.new(@stream)
768
889
  svg.width_and_height
769
890
  end
891
+
892
+ def parse_animated_for_gif
893
+ gif = Gif.new(@stream)
894
+ gif.animated?
895
+ end
770
896
  end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.3
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-01 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: fakeweb
14
+ name: fakeweb-fi
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.3'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.5'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.5'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rdoc
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: test-unit
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  description: FastImage finds the size or type of an image given its uri by fetching
@@ -83,22 +83,21 @@ licenses:
83
83
  metadata: {}
84
84
  post_install_message:
85
85
  rdoc_options:
86
- - --charset=UTF-8
86
+ - "--charset=UTF-8"
87
87
  require_paths:
88
88
  - lib
89
89
  required_ruby_version: !ruby/object:Gem::Requirement
90
90
  requirements:
91
- - - '>='
91
+ - - ">="
92
92
  - !ruby/object:Gem::Version
93
93
  version: 1.9.2
94
94
  required_rubygems_version: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - '>='
96
+ - - ">="
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.0.14.1
100
+ rubygems_version: 3.0.6
102
101
  signing_key:
103
102
  specification_version: 4
104
103
  summary: FastImage - Image info fast