image_size 2.1.2 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e5bf43db03f3e3f62465528a32d65b65592240db8756ef759f17b6b2d0c1f14
4
- data.tar.gz: 4b5cfe6468ba3208528c971ce0873760688dd6a59f170d20fe5dc2934a4ca5ff
3
+ metadata.gz: 2e594fe6ec7b9018dd68867a5feaf557c6c22e7ed667876089fcbe35d6f3104c
4
+ data.tar.gz: a221e99d54a933452712df549e2b8b05ceb85c407b27f482042d35c97dbb95c8
5
5
  SHA512:
6
- metadata.gz: 18e0d5c54eb5a89ec5412f7b8094fe154d02f609f0d1dc217881a9bde7236d35ac7a9fe3f4c0f82d33c57c35d9368ca0c03c411a3b2d4f09f174ed4633f7dbed
7
- data.tar.gz: 4685c93339d37b5d4b59caa697885cad1bfff21c934f0e243abcb7814eb9262bd5ecfbe7f8fcc12e8bd207aa2a1711a5bfa5f764ee74e6ddf31a4b1e926f0744
6
+ metadata.gz: dbc4b3ec562040c3316edfc7412110eec1eef87028100f156e155a65bb38bccba7199b1094daa5ddc62317229a0fbe7241af0ba2089adf6ee03ab7eb4d85c634
7
+ data.tar.gz: db58b0bee4cf294cf44ac5b4afe01c8cd0420b0155e220e378755081ca1a655adb1ac30695966f150b094c648befbd8fb96f31d9a835afbefe1bffbc7ce717b4
@@ -19,8 +19,10 @@ jobs:
19
19
  - '2.6'
20
20
  - '2.7'
21
21
  - '3.0'
22
+ - '3.1'
22
23
  - jruby-9.1
23
24
  - jruby-9.2
25
+ - jruby-9.3
24
26
  fail-fast: false
25
27
  steps:
26
28
  - uses: actions/checkout@v2
@@ -28,13 +30,34 @@ jobs:
28
30
  with:
29
31
  ruby-version: "${{ matrix.ruby }}"
30
32
  bundler-cache: true
31
- - run: bundle exec rspec
32
- rubocop:
33
+ - run: bundle exec rspec --format documentation
34
+ legacy:
33
35
  runs-on: ubuntu-latest
36
+ container: ${{ matrix.container }}
37
+ strategy:
38
+ matrix:
39
+ container:
40
+ - rspec/ci:1.8.7
41
+ - rspec/ci:1.9.3
42
+ fail-fast: false
43
+ steps:
44
+ - uses: actions/checkout@v2
45
+ - run: bundle install
46
+ - run: bundle exec rspec --format documentation
47
+ windows:
48
+ runs-on: windows-latest
49
+ strategy:
50
+ matrix:
51
+ ruby:
52
+ - '2.6'
53
+ - '2.7'
54
+ - '3.0'
55
+ - '3.1'
56
+ fail-fast: false
34
57
  steps:
35
58
  - uses: actions/checkout@v2
36
59
  - uses: ruby/setup-ruby@v1
37
60
  with:
38
- ruby-version: '3.0'
61
+ ruby-version: "${{ matrix.ruby }}"
39
62
  bundler-cache: true
40
- - run: bundle exec rubocop
63
+ - run: bundle exec rspec --format documentation
@@ -0,0 +1,16 @@
1
+ name: rubocop
2
+ on:
3
+ push:
4
+ pull_request:
5
+ schedule:
6
+ - cron: 45 4 * * 3
7
+ jobs:
8
+ rubocop:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+ - uses: ruby/setup-ruby@v1
13
+ with:
14
+ ruby-version: '3.1'
15
+ bundler-cache: true
16
+ - run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -15,6 +15,9 @@ Layout/CaseIndentation:
15
15
  Layout/EndAlignment:
16
16
  EnforcedStyleAlignWith: variable
17
17
 
18
+ Layout/FirstHashElementIndentation:
19
+ EnforcedStyle: consistent
20
+
18
21
  Layout/LineLength:
19
22
  Max: 120
20
23
 
@@ -50,6 +53,9 @@ Style/EmptyCaseCondition:
50
53
  Style/Encoding:
51
54
  Enabled: false
52
55
 
56
+ Style/FileRead:
57
+ Enabled: false
58
+
53
59
  Style/HashEachMethods:
54
60
  Enabled: true
55
61
 
@@ -65,12 +71,18 @@ Style/HashTransformValues:
65
71
  Style/IfUnlessModifier:
66
72
  Enabled: false
67
73
 
74
+ Style/NumericPredicate:
75
+ Enabled: false
76
+
68
77
  Style/ParallelAssignment:
69
78
  Enabled: false
70
79
 
71
80
  Style/SafeNavigation:
72
81
  Enabled: false
73
82
 
83
+ Style/SlicingWithRange:
84
+ Enabled: false
85
+
74
86
  Style/TrailingCommaInArrayLiteral:
75
87
  EnforcedStyleForMultiline: comma
76
88
 
data/.rubocop_todo.yml CHANGED
@@ -9,17 +9,17 @@
9
9
  # Offense count: 8
10
10
  # Configuration parameters: IgnoredMethods.
11
11
  Metrics/AbcSize:
12
- Max: 43
12
+ Enabled: false
13
13
 
14
14
  # Offense count: 5
15
15
  # Configuration parameters: IgnoredMethods.
16
16
  Metrics/CyclomaticComplexity:
17
- Max: 21
17
+ Enabled: false
18
18
 
19
19
  # Offense count: 2
20
20
  # Configuration parameters: IgnoredMethods.
21
21
  Metrics/PerceivedComplexity:
22
- Max: 21
22
+ Enabled: false
23
23
 
24
24
  # Offense count: 8
25
25
  # Cop supports --auto-correct.
data/CHANGELOG.markdown CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## unreleased
4
4
 
5
+ ## v3.0.2 (2022-05-19)
6
+
7
+ * Fix handling empty files [#20](https://github.com/toy/image_size/issues/20) [@toy](https://github.com/toy)
8
+
9
+ ## v3.0.1 (2021-10-21)
10
+
11
+ * Fix reading file chunks starting after EOF and reading chunks non-consecutively [toy/image_optim_rails#12](https://github.com/toy/image_optim_rails/issues/12) [@toy](https://github.com/toy)
12
+
13
+ ## v3.0.0 (2021-10-17)
14
+
15
+ * Read only required chunks of data for files and seekable IOs [@toy](https://github.com/toy)
16
+ * Raise `FormatError` whenever reading data returns less data than expected [#12](https://github.com/toy/image_size/issues/12) [@toy](https://github.com/toy)
17
+ * Add `w`/`width` and `h`/`height` accessors to `Size` [@toy](https://github.com/toy)
18
+
5
19
  ## v2.1.2 (2021-08-21)
6
20
 
7
21
  * Fix for pcx on big endian systems by forcing reading dimensions in little endian byte order [#15](https://github.com/toy/image_size/issues/15) [#16](https://github.com/toy/image_size/pull/16) [@mtasaka](https://github.com/mtasaka)
data/Gemfile CHANGED
@@ -3,3 +3,5 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
+
7
+ gem 'webrick' if RUBY_VERSION >= '3.0'
data/README.markdown CHANGED
@@ -3,8 +3,8 @@
3
3
 
4
4
  # image_size
5
5
 
6
- measure image size using pure Ruby
7
- formats: `apng`, `bmp`, `cur`, `gif`, `ico`, `j2c`, `jp2`, `jpeg`, `jpx`, `mng`, `pam`, `pbm`, `pcx`, `pgm`, `png`, `ppm`, `psd`, `svg`, `swf`, `tiff`, `webp`, `xbm`, `xpm`
6
+ Measure image size using pure Ruby.
7
+ Formats: `apng`, `bmp`, `cur`, `gif`, `ico`, `j2c`, `jp2`, `jpeg`, `jpx`, `mng`, `pam`, `pbm`, `pcx`, `pgm`, `png`, `ppm`, `psd`, `svg`, `swf`, `tiff`, `webp`, `xbm`, `xpm`.
8
8
 
9
9
  ## Installation
10
10
 
@@ -17,26 +17,32 @@ gem install image_size
17
17
  Add to your `Gemfile`:
18
18
 
19
19
  ```ruby
20
- gem 'image_size', '~> 2.0'
20
+ gem 'image_size', '~> 3.0'
21
21
  ```
22
22
 
23
23
  ## Usage
24
24
 
25
25
  ```ruby
26
- image_size = ImageSize.path('spec/test.jpg')
26
+ image_size = ImageSize.path('spec/images/jpeg/436x429.jpeg')
27
27
 
28
28
  image_size.format #=> :jpec
29
- image_size.width #=> 320
30
- image_size.height #=> 240
31
- image_size.w #=> 320
32
- image_size.h #=> 240
33
- image_size.size #=> [320, 240]
29
+ image_size.width #=> 436
30
+ image_size.height #=> 429
31
+ image_size.w #=> 436
32
+ image_size.h #=> 429
33
+ image_size.size #=> [436, 429]
34
+ image_size.size.to_s #=> "436x429"
35
+ "#{image_size.size}" #=> "436x429"
36
+ image_size.size.width #=> 436
37
+ image_size.size.height #=> 429
38
+ image_size.size.w #=> 436
39
+ image_size.size.h #=> 429
34
40
  ```
35
41
 
36
42
  Or using `IO` object:
37
43
 
38
44
  ```ruby
39
- image_size = File.open('spec/test.jpg', 'rb'){ |fh| ImageSize.new(fh) }
45
+ image_size = File.open('spec/images/jpeg/436x429.jpeg', 'rb'){ |fh| ImageSize.new(fh) }
40
46
  ```
41
47
 
42
48
  Any object responding to `read` and `eof?`:
@@ -68,14 +74,14 @@ So rewind if needed before passing to `ImageSize` and/or rewind after passing to
68
74
  ```ruby
69
75
  require 'image_size'
70
76
 
71
- File.open('spec/test.jpg', 'rb') do |fh|
77
+ File.open('spec/images/jpeg/436x429.jpeg', 'rb') do |fh|
72
78
  image_size = ImageSize.new(fh)
73
79
 
74
80
  fh.rewind
75
81
  data = fh.read
76
82
  end
77
83
 
78
- File.open('spec/test.jpg', 'rb') do |fh|
84
+ File.open('spec/images/jpeg/436x429.jpeg', 'rb') do |fh|
79
85
  data = fh.read
80
86
  fh.rewind
81
87
 
@@ -88,4 +94,4 @@ end
88
94
  This code is free to use under the terms of the [Ruby's licence](LICENSE.txt).
89
95
 
90
96
  Original author: Keisuke Minami <keisuke@rccn.com>.\
91
- Further development 2010-2020 Ivan Kuchin https://github.com/toy/image_size
97
+ Further development 2010-2022 Ivan Kuchin https://github.com/toy/image_size
data/image_size.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_size'
5
- s.version = '2.1.2'
5
+ s.version = '3.0.2'
6
6
  s.summary = %q{Measure image size using pure Ruby}
7
7
  s.description = %q{Measure following file dimensions: apng, bmp, cur, gif, ico, j2c, jp2, jpeg, jpx, mng, pam, pbm, pcx, pgm, png, ppm, psd, svg, swf, tiff, webp, xbm, xpm}
8
8
  s.homepage = "https://github.com/toy/#{s.name}"
@@ -22,7 +22,8 @@ Gem::Specification.new do |s|
22
22
  s.require_paths = %w[lib]
23
23
 
24
24
  s.add_development_dependency 'rspec', '~> 3.0'
25
- if RUBY_VERSION >= '2.4'
26
- s.add_development_dependency 'rubocop', '~> 1.0'
25
+ if RUBY_VERSION >= '2.5'
26
+ s.add_development_dependency 'rubocop', '~> 1.22'
27
+ s.add_development_dependency 'rubocop-rspec', '~> 2.0'
27
28
  end
28
29
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_size/reader'
4
+
5
+ class ImageSize
6
+ module ChunkyReader # :nodoc:
7
+ include Reader
8
+
9
+ # Size of a chunk in which to read
10
+ def chunk_size
11
+ 4096
12
+ end
13
+
14
+ # Including class should define method chunk that accepts the chunk number
15
+ # and returns a string of chunk_size length or shorter for last chunk, or
16
+ # nil for further chunks.
17
+ # Determines required chunks, takes parts of them to construct desired
18
+ # substring, behaves same as str[start, length] except start can't be
19
+ # negative.
20
+ def [](offset, length)
21
+ raise ArgumentError, "expected offset not to be negative, got #{offset}" if offset < 0
22
+ return if length < 0
23
+
24
+ first = offset / chunk_size
25
+ return unless (first_chunk = chunk(first))
26
+
27
+ last = (offset + length - 1) / chunk_size
28
+
29
+ if first >= last
30
+ first_chunk[offset - (first * chunk_size), length]
31
+ else
32
+ return unless (first_piece = first_chunk[offset - (first * chunk_size), chunk_size])
33
+
34
+ chunks = (first.succ...last).map{ |i| chunk(i) }.unshift(first_piece)
35
+
36
+ if (last_chunk = chunk(last))
37
+ chunks.push(last_chunk[0, offset + length - (last * chunk_size)])
38
+ end
39
+
40
+ chunks.join
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+ require 'stringio'
5
+
6
+ class ImageSize
7
+ module Reader # :nodoc:
8
+ class << self
9
+ def open(input)
10
+ case
11
+ when input.is_a?(String)
12
+ yield StringReader.new(input)
13
+ when input.is_a?(StringIO)
14
+ yield StringReader.new(input.string)
15
+ when input.respond_to?(:read) && input.respond_to?(:eof?)
16
+ yield for_io(input)
17
+ when input.is_a?(Pathname)
18
+ input.open('rb'){ |f| yield for_io(f) }
19
+ else
20
+ raise ArgumentError, "expected data as String or an object responding to read and eof?, got #{input.class}"
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def for_io(io)
27
+ if io.respond_to?(:stat) && !io.stat.file?
28
+ StreamIOReader.new(io)
29
+ else
30
+ begin
31
+ io.seek(0, IO::SEEK_CUR)
32
+ SeekableIOReader.new(io)
33
+ rescue Errno::ESPIPE, Errno::EINVAL
34
+ StreamIOReader.new(io)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def fetch(offset, length)
41
+ chunk = self[offset, length]
42
+
43
+ unless chunk && chunk.length == length
44
+ raise FormatError, "Expected #{length} bytes at offset #{offset}, got #{chunk.inspect}"
45
+ end
46
+
47
+ chunk
48
+ end
49
+
50
+ def unpack(offset, length, format)
51
+ fetch(offset, length).unpack(format)
52
+ end
53
+
54
+ if ''.respond_to?(:unpack1)
55
+ def unpack1(offset, length, format)
56
+ fetch(offset, length).unpack1(format)
57
+ end
58
+ else
59
+ def unpack1(offset, length, format)
60
+ fetch(offset, length).unpack(format)[0]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_size/chunky_reader'
4
+
5
+ class ImageSize
6
+ class SeekableIOReader # :nodoc:
7
+ include ChunkyReader
8
+
9
+ def initialize(io)
10
+ @io = io
11
+ @pos = 0
12
+ @chunks = {}
13
+ end
14
+
15
+ private
16
+
17
+ def chunk(i)
18
+ unless @chunks.key?(i)
19
+ @io.seek((chunk_size * i) - @pos, IO::SEEK_CUR)
20
+ data = @io.read(chunk_size)
21
+ @pos = chunk_size * i
22
+ @pos += data.length if data
23
+ @chunks[i] = data
24
+ end
25
+
26
+ @chunks[i]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_size/chunky_reader'
4
+
5
+ class ImageSize
6
+ class StreamIOReader # :nodoc:
7
+ include ChunkyReader
8
+
9
+ def initialize(io)
10
+ @io = io
11
+ @chunks = []
12
+ end
13
+
14
+ private
15
+
16
+ def chunk(i)
17
+ @chunks << @io.read(chunk_size) while i >= @chunks.length && !@io.eof?
18
+
19
+ @chunks[i]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_size/reader'
4
+
5
+ class ImageSize
6
+ class StringReader # :nodoc:
7
+ include Reader
8
+
9
+ def initialize(string)
10
+ @string = if string.respond_to?(:encoding) && string.encoding.name != 'ASCII-8BIT'
11
+ string.dup.force_encoding('ASCII-8BIT')
12
+ else
13
+ string
14
+ end
15
+ end
16
+
17
+ def [](offset, length)
18
+ @string[offset, length]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_size/reader'
4
+ require 'image_size/chunky_reader'
5
+
6
+ require 'net/https'
7
+ require 'uri'
8
+
9
+ # This is a hacky experiment and not part of public API
10
+ #
11
+ # It adds ability to fetch size of image from http server while downloading only
12
+ # needed chunks if the server recognises Range header
13
+ class ImageSize
14
+ class URIReader # :nodoc:
15
+ include ChunkyReader
16
+
17
+ def initialize(uri, redirects = 5)
18
+ if !@http || @http.address != uri.host || @http.port != uri.port
19
+ @http.finish if @http
20
+ @http = Net::HTTP.new(uri.host, uri.port)
21
+ @http.use_ssl = true if uri.scheme == 'https'
22
+ @http.start
23
+ end
24
+
25
+ @request_uri = uri.request_uri
26
+ response = request_chunk(0)
27
+
28
+ case response
29
+ when Net::HTTPRedirection
30
+ raise "Too many redirects: #{response['location']}" unless redirects > 0
31
+
32
+ initialize(uri + response['location'], redirects - 1)
33
+ when Net::HTTPOK
34
+ @body = response.body
35
+ when Net::HTTPPartialContent
36
+ @chunks = { 0 => response.body }
37
+ when Net::HTTPRequestedRangeNotSatisfiable
38
+ @body = ''
39
+ else
40
+ raise "Unexpected response: #{response}"
41
+ end
42
+ end
43
+
44
+ def [](offset, length)
45
+ if @body
46
+ @body[offset, length]
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def chunk(i)
53
+ unless @chunks.key?(i)
54
+ response = request_chunk(i)
55
+ case response
56
+ when Net::HTTPPartialContent
57
+ @chunks[i] = response.body
58
+ else
59
+ raise "Unexpected response: #{response}"
60
+ end
61
+ end
62
+
63
+ @chunks[i]
64
+ end
65
+
66
+ private
67
+
68
+ def request_chunk(i)
69
+ @http.get(@request_uri, 'Range' => "bytes=#{chunk_size * i}-#{(chunk_size * (i + 1)) - 1}")
70
+ end
71
+ end
72
+
73
+ module Reader # :nodoc:
74
+ class << self
75
+ def open_with_uri(input, &block)
76
+ if input.is_a?(URI)
77
+ yield URIReader.new(input)
78
+ else
79
+ open_without_uri(input, &block)
80
+ end
81
+ end
82
+ alias_method :open_without_uri, :open
83
+ alias_method :open, :open_with_uri
84
+ end
85
+ end
86
+
87
+ def self.url(url)
88
+ new(url.is_a?(URI) ? url : URI(url))
89
+ end
90
+ end
data/lib/image_size.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # encoding: BINARY
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'stringio'
4
+ require 'image_size/reader'
5
+ require 'image_size/seekable_io_reader'
6
+ require 'image_size/stream_io_reader'
7
+ require 'image_size/string_reader'
5
8
 
6
9
  # Determine image format and size
7
10
  class ImageSize
@@ -13,38 +16,23 @@ class ImageSize
13
16
  def to_s
14
17
  join('x')
15
18
  end
16
- end
17
-
18
- class ImageReader # :nodoc:
19
- attr_reader :data
20
19
 
21
- def initialize(data_or_io)
22
- @io = if data_or_io.is_a?(String)
23
- StringIO.new(data_or_io)
24
- elsif data_or_io.respond_to?(:read) && data_or_io.respond_to?(:eof?)
25
- data_or_io
26
- else
27
- raise ArgumentError, "expected data as String or an object responding to read and eof?, got #{data_or_io.class}"
28
- end
29
- @data = String.new # not frozen
20
+ # get first element
21
+ def width
22
+ self[0]
30
23
  end
24
+ alias_method :w, :width
31
25
 
32
- CHUNK = 1024
33
- def [](offset, length)
34
- while !@io.eof? && @data.length < offset + length
35
- data = @io.read(CHUNK)
36
- break unless data
37
-
38
- data.force_encoding(@data.encoding) if data.respond_to?(:encoding)
39
- @data << data
40
- end
41
- @data[offset, length]
26
+ # get second element
27
+ def height
28
+ self[1]
42
29
  end
30
+ alias_method :h, :height
43
31
  end
44
32
 
45
33
  # Given path to image finds its format, width and height
46
34
  def self.path(path)
47
- File.open(path, 'rb'){ |f| new(f) }
35
+ new(Pathname.new(path))
48
36
  end
49
37
 
50
38
  # Used for svg
@@ -59,11 +47,10 @@ class ImageSize
59
47
 
60
48
  # Given image as any class responding to read and eof? or data as String, finds its format and dimensions
61
49
  def initialize(data)
62
- ir = ImageReader.new(data)
63
- @format = detect_format(ir)
64
- return unless @format
65
-
66
- @width, @height = send("size_of_#{@format}", ir)
50
+ Reader.open(data) do |ir|
51
+ @format = detect_format(ir)
52
+ @width, @height = send("size_of_#{@format}", ir) if @format
53
+ end
67
54
  end
68
55
 
69
56
  # Image format
@@ -89,6 +76,7 @@ private
89
76
  def detect_format(ir)
90
77
  head = ir[0, 1024]
91
78
  case
79
+ when head.nil? || head.empty? then nil
92
80
  when head[0, 6] =~ /GIF8[79]a/ then :gif
93
81
  when head[0, 8] == "\211PNG\r\n\032\n" then detect_png_type(ir)
94
82
  when head[0, 8] == "\212MNG\r\n\032\n" then :mng
@@ -100,7 +88,7 @@ private
100
88
  when head =~ %r{/\* XPM \*/} then :xpm
101
89
  when head[0, 4] == '8BPS' then :psd
102
90
  when head[0, 3] =~ /[FC]WS/ then :swf
103
- when head =~ SVG_R || (head =~ XML_R && ir[0, 4096][SVG_R]) then :svg
91
+ when head =~ SVG_R || (head =~ XML_R && ir[0, 4096] =~ SVG_R) then :svg
104
92
  when head[0, 2] =~ /\n[\0-\5]/ then :pcx
105
93
  when head[0, 12] =~ /RIFF(?m:....)WEBP/ then :webp
106
94
  when head[0, 4] == "\0\0\1\0" then :ico
@@ -117,7 +105,7 @@ private
117
105
  break if ['IDAT', 'IEND', nil].include?(type)
118
106
  return :apng if type == 'acTL'
119
107
 
120
- length = ir[offset, 4].unpack('N')[0]
108
+ length = ir.unpack1(offset, 4, 'N')
121
109
  offset += 8 + length + 4
122
110
  end
123
111
  :png
@@ -144,7 +132,7 @@ private
144
132
  end
145
133
 
146
134
  def size_of_gif(ir)
147
- ir[6, 4].unpack('vv')
135
+ ir.unpack(6, 4, 'vv')
148
136
  end
149
137
 
150
138
  def size_of_mng(ir)
@@ -152,7 +140,7 @@ private
152
140
  raise FormatError, 'MHDR not in place for MNG'
153
141
  end
154
142
 
155
- ir[16, 8].unpack('NN')
143
+ ir.unpack(16, 8, 'NN')
156
144
  end
157
145
 
158
146
  def size_of_png(ir)
@@ -160,7 +148,7 @@ private
160
148
  raise FormatError, 'IHDR not in place for PNG'
161
149
  end
162
150
 
163
- ir[16, 8].unpack('NN')
151
+ ir.unpack(16, 8, 'NN')
164
152
  end
165
153
  alias_method :size_of_apng, :size_of_png
166
154
 
@@ -178,11 +166,11 @@ private
178
166
  offset += 1 until section_marker != ir[offset + 1, 1]
179
167
  raise FormatError, 'EOF in JPEG' if ir[offset, 1].nil?
180
168
 
181
- _marker, code, length = ir[offset, 4].unpack('aCn')
169
+ code, length = ir.unpack(offset, 4, 'xCn')
182
170
  offset += 4
183
171
 
184
172
  if JPEG_CODE_CHECK.include?(code)
185
- return ir[offset + 1, 4].unpack('nn').reverse
173
+ return ir.unpack(offset + 1, 4, 'nn').reverse
186
174
  end
187
175
 
188
176
  offset += length - 2
@@ -190,11 +178,11 @@ private
190
178
  end
191
179
 
192
180
  def size_of_bmp(ir)
193
- header_size = ir[14, 4].unpack('V')[0]
181
+ header_size = ir.unpack1(14, 4, 'V')
194
182
  if header_size == 12
195
- ir[18, 4].unpack('vv')
183
+ ir.unpack(18, 4, 'vv')
196
184
  else
197
- ir[18, 8].unpack('VV').map do |n|
185
+ ir.unpack(18, 8, 'VV').map do |n|
198
186
  if n > 0x7fff_ffff
199
187
  0x1_0000_0000 - n # absolute value of converted to signed
200
188
  else
@@ -216,7 +204,7 @@ private
216
204
  def size_of_pam(ir)
217
205
  width = height = nil
218
206
  offset = 3
219
- loop do
207
+ until width && height
220
208
  if ir[offset, 1] == '#'
221
209
  offset += 1 until ["\n", '', nil].include?(ir[offset, 1])
222
210
  offset += 1
@@ -235,7 +223,6 @@ private
235
223
  raise FormatError, "Unexpected data in PAM header: #{chunk.inspect}"
236
224
  end
237
225
  offset += $&.length
238
- break if width && height
239
226
  end
240
227
  end
241
228
  [width, height]
@@ -259,23 +246,23 @@ private
259
246
  end
260
247
 
261
248
  def size_of_psd(ir)
262
- ir[14, 8].unpack('NN').reverse
249
+ ir.unpack(14, 8, 'NN').reverse
263
250
  end
264
251
 
265
252
  def size_of_tiff(ir)
266
- endian2b = ir[0, 4] == "II*\000" ? 'v' : 'n'
253
+ endian2b = ir.fetch(0, 4) == "II*\000" ? 'v' : 'n'
267
254
  endian4b = endian2b.upcase
268
255
  packspec = [nil, 'C', nil, endian2b, endian4b, nil, 'c', nil, endian2b, endian4b]
269
256
 
270
- offset = ir[4, 4].unpack(endian4b)[0]
271
- num_dirent = ir[offset, 2].unpack(endian2b)[0]
257
+ offset = ir.unpack1(4, 4, endian4b)
258
+ num_dirent = ir.unpack1(offset, 2, endian2b)
272
259
  offset += 2
273
260
  num_dirent = offset + (num_dirent * 12)
274
261
 
275
262
  width = height = nil
276
263
  until width && height
277
- ifd = ir[offset, 12]
278
- raise FormatError, 'Reached end of directory entries in TIFF' if ifd.nil? || offset > num_dirent
264
+ ifd = ir.fetch(offset, 12)
265
+ raise FormatError, 'Reached end of directory entries in TIFF' if offset > num_dirent
279
266
 
280
267
  tag, type = ifd.unpack(endian2b * 2)
281
268
  offset += 12
@@ -294,14 +281,14 @@ private
294
281
  end
295
282
 
296
283
  def size_of_pcx(ir)
297
- parts = ir[4, 8].unpack('v4')
284
+ parts = ir.unpack(4, 8, 'v4')
298
285
  [parts[2] - parts[0] + 1, parts[3] - parts[1] + 1]
299
286
  end
300
287
 
301
288
  def size_of_swf(ir)
302
- value_bit_length = ir[8, 1].unpack('B5').first.to_i(2)
303
- bit_length = 5 + value_bit_length * 4
304
- rect_bits = ir[8, bit_length / 8 + 1].unpack("B#{bit_length}").first
289
+ value_bit_length = ir.unpack1(8, 1, 'B5').to_i(2)
290
+ bit_length = 5 + (value_bit_length * 4)
291
+ rect_bits = ir.unpack1(8, (bit_length / 8) + 1, "B#{bit_length}")
305
292
  values = rect_bits[5..-1].unpack("a#{value_bit_length}" * 4).map{ |bits| bits.to_i(2) }
306
293
  x_min, x_max, y_min, y_max = values
307
294
  [(x_max - x_min) / 20, (y_max - y_min) / 20]
@@ -309,7 +296,8 @@ private
309
296
 
310
297
  def size_of_svg(ir)
311
298
  attributes = {}
312
- ir.data[SVG_R, 1].scan(/(\S+)=(?:'([^']*)'|"([^"]*)"|([^'"\s]*))/) do |name, v0, v1, v2|
299
+ svg_tag = ir[0, 1024][SVG_R, 1] || ir[0, 4096][SVG_R, 1]
300
+ svg_tag.scan(/(\S+)=(?:'([^']*)'|"([^"]*)"|([^'"\s]*))/) do |name, v0, v1, v2|
313
301
  attributes[name] = v0 || v1 || v2
314
302
  end
315
303
  dpi = self.class.dpi
@@ -330,20 +318,20 @@ private
330
318
  end
331
319
 
332
320
  def size_of_ico(ir)
333
- ir[6, 2].unpack('CC').map{ |v| v.zero? ? 256 : v }
321
+ ir.unpack(6, 2, 'CC').map{ |v| v.zero? ? 256 : v }
334
322
  end
335
323
  alias_method :size_of_cur, :size_of_ico
336
324
 
337
325
  def size_of_webp(ir)
338
- case ir[12, 4]
326
+ case ir.fetch(12, 4)
339
327
  when 'VP8 '
340
- ir[26, 4].unpack('vv').map{ |v| v & 0x3fff }
328
+ ir.unpack(26, 4, 'vv').map{ |v| v & 0x3fff }
341
329
  when 'VP8L'
342
- n = ir[21, 4].unpack('V')[0]
343
- [(n & 0x3fff) + 1, (n >> 14 & 0x3fff) + 1]
330
+ n = ir.unpack1(21, 4, 'V')
331
+ [(n & 0x3fff) + 1, ((n >> 14) & 0x3fff) + 1]
344
332
  when 'VP8X'
345
- w16, w8, h16, h8 = ir[24, 6].unpack('vCvC')
346
- [(w16 | w8 << 16) + 1, (h16 | h8 << 16) + 1]
333
+ w16, w8, h16, h8 = ir.unpack(24, 6, 'vCvC')
334
+ [(w16 | (w8 << 16)) + 1, (h16 | (h8 << 16)) + 1]
347
335
  end
348
336
  end
349
337
 
@@ -355,13 +343,13 @@ private
355
343
  break if stop && offset >= stop
356
344
  break if ir[offset, 4] == '' || ir[offset, 4].nil?
357
345
 
358
- size = ir[offset, 4].unpack('N')[0]
359
- type = ir[offset + 4, 4]
346
+ size = ir.unpack1(offset, 4, 'N')
347
+ type = ir.fetch(offset + 4, 4)
360
348
 
361
349
  data_offset = 8
362
350
  case size
363
351
  when 1
364
- size = ir[offset, 8].unpack('Q>')[0]
352
+ size = ir.unpack1(offset, 8, 'Q>')
365
353
  data_offset = 16
366
354
  raise FormatError, "Unexpected xl-box size #{size}" if (1..15).include?(size)
367
355
  when 2..7
@@ -373,7 +361,7 @@ private
373
361
  offset += data_offset
374
362
  in_header = true
375
363
  elsif in_header && type == 'ihdr'
376
- return ir[offset + data_offset, 8].unpack('NN').reverse
364
+ return ir.unpack(offset + data_offset, 8, 'NN').reverse
377
365
  else
378
366
  break if size.zero? # box to the end of file
379
367
 
@@ -384,6 +372,6 @@ private
384
372
  alias_method :size_of_jpx, :size_of_jp2
385
373
 
386
374
  def size_of_j2c(ir)
387
- ir[8, 8].unpack('NN')
375
+ ir.unpack(8, 8, 'NN')
388
376
  end
389
377
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+
5
+ require 'image_size/chunky_reader'
6
+
7
+ describe ImageSize::ChunkyReader do
8
+ context :[] do
9
+ test_reader = Class.new do
10
+ include ImageSize::ChunkyReader
11
+
12
+ def initialize(string)
13
+ @string = string
14
+ end
15
+
16
+ private
17
+
18
+ def chunk(i)
19
+ @string[i * chunk_size, chunk_size]
20
+ end
21
+ end
22
+
23
+ custom_chunk_size_reader = Class.new(test_reader) do
24
+ def chunk_size
25
+ 100
26
+ end
27
+ end
28
+
29
+ {
30
+ 'empty string' => '',
31
+ 'a bit of data' => 'foo bar baz',
32
+ 'a lot of data' => File.open('GPL', 'rb', &:read),
33
+ }.each do |data_description, data|
34
+ {
35
+ 'default' => test_reader.new(data),
36
+ 'custom' => custom_chunk_size_reader.new(data),
37
+ }.each do |chunk_size_description, reader|
38
+ context "for #{data_description} using reader with #{chunk_size_description} chunk size" do
39
+ it 'raises ArgumentError for negative offset' do
40
+ [-1, 0, 1, 100].each do |length|
41
+ expect{ reader[-1, length] }.to raise_exception(ArgumentError)
42
+ end
43
+ end
44
+
45
+ it 'behaves same as fetching a string for any offset and length' do
46
+ full_chunks = data.length / reader.chunk_size
47
+ offsets = [0, 1, full_chunks - 1, full_chunks, full_chunks + 1].map do |i|
48
+ [-1, 0, 1].map do |add|
49
+ (i * reader.chunk_size) + add
50
+ end
51
+ end.flatten
52
+
53
+ offsets.each do |offset|
54
+ next if offset < 0
55
+
56
+ offsets.each do |offset_b|
57
+ length = offset_b - offset
58
+ expect(reader[offset, length]).to eq(data[offset, length]),
59
+ "for offset #{offset} and length #{length}\n"\
60
+ "expected: #{data[offset, length].inspect}\n"\
61
+ " got: #{reader[offset, length].inspect}"
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec'
4
+
5
+ require 'image_size/seekable_io_reader'
6
+
7
+ describe ImageSize::SeekableIOReader do
8
+ context :[] do
9
+ def ios
10
+ @ios ||= []
11
+ end
12
+
13
+ def io
14
+ File.open('GPL', 'rb').tap do |io|
15
+ ios << io
16
+ end
17
+ end
18
+
19
+ after do
20
+ ios.pop.close until ios.empty?
21
+ end
22
+
23
+ def new_reader
24
+ ImageSize::SeekableIOReader.new(io)
25
+ end
26
+
27
+ let(:content){ io.read }
28
+
29
+ it 'reads as expected when pieces are read consecutively' do
30
+ reader = new_reader
31
+ 0.step(content.length + 4096, 100) do |offset|
32
+ expect(reader[offset, 100]).to eq(content[offset, 100])
33
+ end
34
+ end
35
+
36
+ it 'reads as expected when pieces are read backwards' do
37
+ reader = new_reader
38
+ (content.length + 4096).step(0, -100) do |offset|
39
+ expect(reader[offset, 100]).to eq(content[offset, 100])
40
+ end
41
+ end
42
+
43
+ it 'reads as expected when pieces are read in random order' do
44
+ 100.times do
45
+ reader = new_reader
46
+ 0.step(content.length + 4096, 100).to_a.shuffle.each do |offset|
47
+ expect(reader[offset, 100]).to eq(content[offset, 100])
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,15 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rspec'
4
+
4
5
  require 'image_size'
6
+ require 'image_size/uri_reader'
7
+
5
8
  require 'tempfile'
9
+ require 'shellwords'
10
+ require 'webrick'
6
11
 
7
12
  describe ImageSize do
8
- max_filesize = 16_384
13
+ before :all do
14
+ @server = WEBrick::HTTPServer.new({
15
+ :Logger => WEBrick::Log.new(StringIO.new),
16
+ :AccessLog => [],
17
+ :BindAddress => '127.0.0.1',
18
+ :Port => 0, # get the next available port
19
+ :DocumentRoot => '.',
20
+ })
21
+ @server_thread = Thread.new{ @server.start }
22
+ @server_base_url = URI("http://127.0.0.1:#{@server.config[:Port]}/")
23
+ end
9
24
 
10
- (Dir['spec/images/*/*.*'] + [__FILE__]).each do |path|
11
- filesize = File.size(path)
12
- warn "#{path} is too big #{filesize} (max #{max_filesize})" if filesize > max_filesize
25
+ after :all do
26
+ @server.shutdown
27
+ @server_thread.join
28
+ end
29
+
30
+ Dir['spec/**/*'].each do |path|
31
+ next unless File.file?(path)
13
32
 
14
33
  describe "for #{path}" do
15
34
  let(:name){ File.basename(path) }
@@ -27,6 +46,15 @@ describe ImageSize do
27
46
  }
28
47
  end
29
48
  let(:file_data){ File.open(path, 'rb', &:read) }
49
+ let(:file_size){ file_data.length }
50
+
51
+ before do
52
+ max_file_size = 16_384
53
+
54
+ if file_size > max_file_size
55
+ raise "reduce resulting gem size, #{path} is too big (#{file_size} > #{max_file_size})"
56
+ end
57
+ end
30
58
 
31
59
  context 'given as data' do
32
60
  it 'gets format and dimensions' do
@@ -43,20 +71,33 @@ describe ImageSize do
43
71
  image_size = ImageSize.new(io)
44
72
  expect(image_size).to have_attributes(attributes)
45
73
  expect(io).not_to be_closed
46
- expect(io.pos).to_not be_zero
74
+ if file_size.zero?
75
+ expect(io.pos).to be_zero
76
+ else
77
+ expect(io.pos).to_not be_zero
78
+ end
47
79
  io.rewind
48
80
  expect(io.read).to eq(file_data)
49
81
  end
50
82
  end
51
83
  end
52
84
 
85
+ context 'given as unseekable IO' do
86
+ it 'gets format and dimensions' do
87
+ IO.popen(%W[cat #{path}].shelljoin, 'rb') do |io|
88
+ image_size = ImageSize.new(io)
89
+ expect(image_size).to have_attributes(attributes)
90
+ expect(io).not_to be_closed
91
+ end
92
+ end
93
+ end
94
+
53
95
  context 'given as StringIO' do
54
96
  it 'gets format and dimensions' do
55
97
  io = StringIO.new(file_data)
56
98
  image_size = ImageSize.new(io)
57
99
  expect(image_size).to have_attributes(attributes)
58
100
  expect(io).not_to be_closed
59
- expect(io.pos).to_not be_zero
60
101
  io.rewind
61
102
  expect(io.read).to eq(file_data)
62
103
  end
@@ -71,7 +112,11 @@ describe ImageSize do
71
112
  image_size = ImageSize.new(io)
72
113
  expect(image_size).to have_attributes(attributes)
73
114
  expect(io).not_to be_closed
74
- expect(io.pos).to_not be_zero
115
+ if file_size.zero?
116
+ expect(io.pos).to be_zero
117
+ else
118
+ expect(io.pos).to_not be_zero
119
+ end
75
120
  io.rewind
76
121
  expect(io.read).to eq(file_data)
77
122
  end
@@ -84,6 +129,13 @@ describe ImageSize do
84
129
  expect(image_size).to have_attributes(attributes)
85
130
  end
86
131
  end
132
+
133
+ context 'fetching from webserver' do
134
+ it 'gets format and dimensions' do
135
+ image_size = ImageSize.url(@server_base_url + path)
136
+ expect(image_size).to have_attributes(attributes)
137
+ end
138
+ end
87
139
  end
88
140
  end
89
141
 
@@ -0,0 +1 @@
1
+ * -text
data/spec/images/empty ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ <svg width="1in" height="100" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="36" cy="50" r="30" stroke="black" stroke-width="10" fill="red" />
3
+ </svg>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!--[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]-->
3
+ <!--[ [[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]] ]-->
4
+ <!--[ [ [[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]] ] ]-->
5
+ <!--[ [ [ [[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]] ] ] ]-->
6
+ <!--[ [ [ [ [[[[[[[[[[[[]]]]]]]]]]]] ] ] ] ]-->
7
+ <!--[ [ [ [ [ [[[[[[[[]]]]]]]] ] ] ] ] ]-->
8
+ <!--[ [ [ [ [ [ [[[[]]]] ] ] ] ] ] ]-->
9
+ <!--[ [ [ [ [ [ [ ] ] ] ] ] ] ]-->
10
+ <!--[ [ [ [ [ [ [ ] ] ] ] ] ] ]-->
11
+ <!--[ [ [ [ [ [ [[[[]]]] ] ] ] ] ] ]-->
12
+ <!--[ [ [ [ [ [[[[[[[[]]]]]]]] ] ] ] ] ]-->
13
+ <!--[ [ [ [ [[[[[[[[[[[[]]]]]]]]]]]] ] ] ] ]-->
14
+ <!--[ [ [ [[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]] ] ] ]-->
15
+ <!--[ [ [[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]] ] ]-->
16
+ <!--[ [[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]] ]-->
17
+ <!--[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]-->
18
+ <svg width="1in" height="100" xmlns="http://www.w3.org/2000/svg">
19
+ <circle cx="36" cy="50" r="30" stroke="black" stroke-width="10" fill="red" />
20
+ </svg>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!--[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]-->
3
+ <!--[ [[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]] ]-->
4
+ <!--[ [ [[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]] ] ]-->
5
+ <!--[ [ [ [[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]] ] ] ]-->
6
+ <!--[ [ [ [ [[[[[[[[[[[[]]]]]]]]]]]] ] ] ] ]-->
7
+ <!--[ [ [ [ [ [[[[[[[[]]]]]]]] ] ] ] ] ]-->
8
+ <!--[ [ [ [ [ [ [[[[]]]] ] ] ] ] ] ]-->
9
+ <!--[ [ [ [ [ [ [ ] ] ] ] ] ] ]-->
10
+ <!--[ [ [ [ [ [ [ ] ] ] ] ] ] ]-->
11
+ <!--[ [ [ [ [ [ [[[[]]]] ] ] ] ] ] ]-->
12
+ <!--[ [ [ [ [ [[[[[[[[]]]]]]]] ] ] ] ] ]-->
13
+ <!--[ [ [ [ [[[[[[[[[[[[]]]]]]]]]]]] ] ] ] ]-->
14
+ <!--[ [ [ [[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]] ] ] ]-->
15
+ <!--[ [ [[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]] ] ]-->
16
+ <!--[ [[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]] ]-->
17
+ <!--[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]-->
18
+ <svg width="1in" height="100" xmlns="http://www.w3.org/2000/svg">
19
+ <circle cx="36" cy="50" r="30" stroke="black" stroke-width="10" fill="red" />
20
+ </svg>
@@ -0,0 +1,11 @@
1
+ #define cursor_width 16
2
+ #define cursor_height 32
3
+ static unsigned char cursor_bits[] = {
4
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x84, 0x10,
7
+ 0xe8, 0x0b, 0x90, 0x04, 0xa8, 0x0a, 0x88, 0x08,
8
+ 0xfe, 0x3f, 0x88, 0x08, 0xa8, 0x0a, 0x90, 0x04,
9
+ 0xe8, 0x0b, 0x84, 0x10, 0x80, 0x00, 0x00, 0x00,
10
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -0,0 +1,40 @@
1
+ /* XPM */
2
+ static char *test2[] = {
3
+ /* columns rows colors chars-per-pixel */
4
+ "24 32 2 1 ",
5
+ " c red",
6
+ ". c white",
7
+ /* pixels */
8
+ "........................",
9
+ "........................",
10
+ "........................",
11
+ "........................",
12
+ "........................",
13
+ "........................",
14
+ ".. .................. ",
15
+ ".. ................ ",
16
+ "... .............. .",
17
+ ".... ............ ..",
18
+ "..... .......... ...",
19
+ "...... ........ ....",
20
+ "....... ...... .....",
21
+ "........ .... ......",
22
+ "......... .. .......",
23
+ ".......... ........",
24
+ "........... .........",
25
+ "............ .........",
26
+ "........... ........",
27
+ ".......... . .......",
28
+ "......... ... ......",
29
+ "........ ..... .....",
30
+ "....... ....... ....",
31
+ "...... ......... ...",
32
+ "..... ........... ..",
33
+ ".... ............. .",
34
+ "... ............... ",
35
+ ".. ................. ",
36
+ ".. ................... ",
37
+ "........................",
38
+ "........................",
39
+ "........................"
40
+ };
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_size
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keisuke Minami
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-08-21 00:00:00.000000000 Z
12
+ date: 2022-05-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -31,14 +31,28 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '1.0'
34
+ version: '1.22'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '1.0'
41
+ version: '1.22'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rubocop-rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
42
56
  description: 'Measure following file dimensions: apng, bmp, cur, gif, ico, j2c, jp2,
43
57
  jpeg, jpx, mng, pam, pbm, pcx, pgm, png, ppm, psd, svg, swf, tiff, webp, xbm, xpm'
44
58
  email:
@@ -47,6 +61,7 @@ extensions: []
47
61
  extra_rdoc_files: []
48
62
  files:
49
63
  - ".github/workflows/check.yml"
64
+ - ".github/workflows/rubocop.yml"
50
65
  - ".gitignore"
51
66
  - ".rubocop.yml"
52
67
  - ".rubocop_todo.yml"
@@ -57,11 +72,21 @@ files:
57
72
  - README.markdown
58
73
  - image_size.gemspec
59
74
  - lib/image_size.rb
75
+ - lib/image_size/chunky_reader.rb
76
+ - lib/image_size/reader.rb
77
+ - lib/image_size/seekable_io_reader.rb
78
+ - lib/image_size/stream_io_reader.rb
79
+ - lib/image_size/string_reader.rb
80
+ - lib/image_size/uri_reader.rb
81
+ - spec/image_size/chunky_reader_spec.rb
82
+ - spec/image_size/seekable_io_reader_spec.rb
60
83
  - spec/image_size_spec.rb
84
+ - spec/images/.gitattributes
61
85
  - spec/images/bmp/v2.42x50.bmp
62
86
  - spec/images/bmp/v3-bottom2top.42x50.bmp
63
87
  - spec/images/bmp/v3-top2bottom.42x50.bmp
64
88
  - spec/images/cur/32x256.cur
89
+ - spec/images/empty
65
90
  - spec/images/gif/668x481.gif
66
91
  - spec/images/ico/32x256.ico
67
92
  - spec/images/jp2/163x402.jp2
@@ -82,6 +107,9 @@ files:
82
107
  - spec/images/pnm/ascii.22x25.ppm
83
108
  - spec/images/psd/16x20.psd
84
109
  - spec/images/svg/72x100.svg
110
+ - spec/images/svg/crlf.72x100.svg
111
+ - spec/images/svg/long.72x100.svg
112
+ - spec/images/svg/long.crlf.72x100.svg
85
113
  - spec/images/swf/450x200.swf
86
114
  - spec/images/tiff/big-endian.68x49.tiff
87
115
  - spec/images/tiff/little-endian.40x68.tiff
@@ -89,14 +117,16 @@ files:
89
117
  - spec/images/webp/lossless.16x32.webp
90
118
  - spec/images/webp/lossy.16x32.webp
91
119
  - spec/images/xbm/16x32.xbm
120
+ - spec/images/xbm/crlf.16x32.xbm
92
121
  - spec/images/xpm/24x32.xpm
122
+ - spec/images/xpm/crlf.24x32.xpm
93
123
  homepage: https://github.com/toy/image_size
94
124
  licenses:
95
125
  - Ruby
96
126
  metadata:
97
127
  bug_tracker_uri: https://github.com/toy/image_size/issues
98
128
  changelog_uri: https://github.com/toy/image_size/blob/master/CHANGELOG.markdown
99
- documentation_uri: https://www.rubydoc.info/gems/image_size/2.1.2
129
+ documentation_uri: https://www.rubydoc.info/gems/image_size/3.0.2
100
130
  source_code_uri: https://github.com/toy/image_size
101
131
  post_install_message:
102
132
  rdoc_options: []
@@ -113,16 +143,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
143
  - !ruby/object:Gem::Version
114
144
  version: '0'
115
145
  requirements: []
116
- rubygems_version: 3.2.16
146
+ rubygems_version: 3.3.11
117
147
  signing_key:
118
148
  specification_version: 4
119
149
  summary: Measure image size using pure Ruby
120
150
  test_files:
151
+ - spec/image_size/chunky_reader_spec.rb
152
+ - spec/image_size/seekable_io_reader_spec.rb
121
153
  - spec/image_size_spec.rb
154
+ - spec/images/.gitattributes
122
155
  - spec/images/bmp/v2.42x50.bmp
123
156
  - spec/images/bmp/v3-bottom2top.42x50.bmp
124
157
  - spec/images/bmp/v3-top2bottom.42x50.bmp
125
158
  - spec/images/cur/32x256.cur
159
+ - spec/images/empty
126
160
  - spec/images/gif/668x481.gif
127
161
  - spec/images/ico/32x256.ico
128
162
  - spec/images/jp2/163x402.jp2
@@ -143,6 +177,9 @@ test_files:
143
177
  - spec/images/pnm/ascii.22x25.ppm
144
178
  - spec/images/psd/16x20.psd
145
179
  - spec/images/svg/72x100.svg
180
+ - spec/images/svg/crlf.72x100.svg
181
+ - spec/images/svg/long.72x100.svg
182
+ - spec/images/svg/long.crlf.72x100.svg
146
183
  - spec/images/swf/450x200.swf
147
184
  - spec/images/tiff/big-endian.68x49.tiff
148
185
  - spec/images/tiff/little-endian.40x68.tiff
@@ -150,4 +187,6 @@ test_files:
150
187
  - spec/images/webp/lossless.16x32.webp
151
188
  - spec/images/webp/lossy.16x32.webp
152
189
  - spec/images/xbm/16x32.xbm
190
+ - spec/images/xbm/crlf.16x32.xbm
153
191
  - spec/images/xpm/24x32.xpm
192
+ - spec/images/xpm/crlf.24x32.xpm