image_size 2.1.2 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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