image_size 2.0.2 → 3.0.0
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 +4 -4
- data/.github/workflows/check.yml +69 -0
- data/.rubocop.yml +27 -4
- data/.rubocop_todo.yml +11 -8
- data/CHANGELOG.markdown +19 -0
- data/GPL +340 -0
- data/Gemfile +1 -3
- data/LICENSE.txt +56 -0
- data/README.markdown +22 -18
- data/image_size.gemspec +6 -5
- data/lib/image_size/chunky_reader.rb +44 -0
- data/lib/image_size/reader.rb +64 -0
- data/lib/image_size/seekable_io_reader.rb +28 -0
- data/lib/image_size/stream_io_reader.rb +22 -0
- data/lib/image_size/string_reader.rb +21 -0
- data/lib/image_size/uri_reader.rb +88 -0
- data/lib/image_size.rb +159 -85
- data/spec/image_size/chunky_reader_spec.rb +69 -0
- data/spec/image_size_spec.rb +45 -2
- data/spec/images/.gitattributes +1 -0
- data/spec/images/cur/32x256.cur +0 -0
- data/spec/images/ico/32x256.ico +0 -0
- data/spec/images/jp2/163x402.jp2 +0 -0
- data/spec/images/jp2/176x373.jpx +0 -0
- data/spec/images/jp2/224x293.j2c +0 -0
- data/spec/images/jpeg/436x429.jpeg +0 -0
- data/spec/images/jpeg/extraneous-bytes.436x429.jpeg +0 -0
- data/spec/images/mng/61x42.mng +0 -0
- data/spec/images/{apng → png}/192x110.apng +0 -0
- data/spec/images/pnm/22x25.pam +8 -0
- data/spec/images/pnm/22x25.pbm +0 -0
- data/spec/images/pnm/22x25.pgm +4 -0
- data/spec/images/pnm/22x25.ppm +4 -0
- data/spec/images/pnm/ascii.22x25.pbm +27 -0
- data/spec/images/pnm/ascii.22x25.pgm +28 -0
- data/spec/images/pnm/ascii.22x25.ppm +28 -0
- data/spec/images/svg/crlf.72x100.svg +3 -0
- data/spec/images/svg/long.72x100.svg +20 -0
- data/spec/images/svg/long.crlf.72x100.svg +20 -0
- data/spec/images/tiff/big-endian.68x49.tiff +0 -0
- data/spec/images/tiff/little-endian.40x68.tiff +0 -0
- data/spec/images/xbm/crlf.16x32.xbm +11 -0
- data/spec/images/xpm/crlf.24x32.xpm +40 -0
- metadata +86 -32
- data/.travis.yml +0 -24
- data/spec/images/cur/50x256.cur +0 -0
- data/spec/images/ico/256x27.ico +0 -0
- data/spec/images/jpeg/320x240.jpeg +0 -0
- data/spec/images/jpeg/extraneous-bytes.320x240.jpeg +0 -0
- data/spec/images/mng/612x132.mng +0 -0
- data/spec/images/pbm/85x55.pbm +0 -0
- data/spec/images/pgm/90x55.pgm +0 -5
- data/spec/images/tiff/48x64.tiff +0 -0
data/lib/image_size.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# encoding: BINARY
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require '
|
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,37 +16,23 @@ class ImageSize
|
|
13
16
|
def to_s
|
14
17
|
join('x')
|
15
18
|
end
|
16
|
-
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@io = if data_or_io.is_a?(String)
|
22
|
-
StringIO.new(data_or_io)
|
23
|
-
elsif data_or_io.respond_to?(:read) && data_or_io.respond_to?(:eof?)
|
24
|
-
data_or_io
|
25
|
-
else
|
26
|
-
raise ArgumentError, "expected data as String or an object responding to read and eof?, got #{data_or_io.class}"
|
27
|
-
end
|
28
|
-
@data = String.new # not frozen
|
20
|
+
# get first element
|
21
|
+
def width
|
22
|
+
self[0]
|
29
23
|
end
|
24
|
+
alias_method :w, :width
|
30
25
|
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
data = @io.read(CHUNK)
|
35
|
-
break unless data
|
36
|
-
|
37
|
-
data.force_encoding(@data.encoding) if data.respond_to?(:encoding)
|
38
|
-
@data << data
|
39
|
-
end
|
40
|
-
@data[offset, length]
|
26
|
+
# get second element
|
27
|
+
def height
|
28
|
+
self[1]
|
41
29
|
end
|
30
|
+
alias_method :h, :height
|
42
31
|
end
|
43
32
|
|
44
33
|
# Given path to image finds its format, width and height
|
45
34
|
def self.path(path)
|
46
|
-
|
35
|
+
new(Pathname.new(path))
|
47
36
|
end
|
48
37
|
|
49
38
|
# Used for svg
|
@@ -58,11 +47,10 @@ class ImageSize
|
|
58
47
|
|
59
48
|
# Given image as any class responding to read and eof? or data as String, finds its format and dimensions
|
60
49
|
def initialize(data)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@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
|
66
54
|
end
|
67
55
|
|
68
56
|
# Image format
|
@@ -84,28 +72,28 @@ class ImageSize
|
|
84
72
|
private
|
85
73
|
|
86
74
|
SVG_R = /<svg\b([^>]*)>/.freeze
|
75
|
+
XML_R = /<\?xml|<!--/.freeze
|
87
76
|
def detect_format(ir)
|
88
77
|
head = ir[0, 1024]
|
89
78
|
case
|
90
|
-
when head[0, 6] =~ /GIF8[79]a/
|
91
|
-
when head[0, 8] == "\211PNG\r\n\032\n"
|
92
|
-
when head[0, 8] == "\212MNG\r\n\032\n"
|
93
|
-
when head[0, 2] == "\377\330"
|
94
|
-
when head[0, 2] == 'BM'
|
95
|
-
when head[0,
|
96
|
-
when head =~ /\#define\s+\S+\s+\d+/
|
97
|
-
when head[0, 4]
|
98
|
-
when head
|
99
|
-
when head
|
100
|
-
when head[0,
|
101
|
-
when head[0,
|
102
|
-
when head[
|
103
|
-
|
104
|
-
|
105
|
-
when head[0,
|
106
|
-
when head[0, 12]
|
107
|
-
when head[0, 4] == "\
|
108
|
-
when head[0, 4] == "\000\000\002\000" then :cur
|
79
|
+
when head[0, 6] =~ /GIF8[79]a/ then :gif
|
80
|
+
when head[0, 8] == "\211PNG\r\n\032\n" then detect_png_type(ir)
|
81
|
+
when head[0, 8] == "\212MNG\r\n\032\n" then :mng
|
82
|
+
when head[0, 2] == "\377\330" then :jpeg
|
83
|
+
when head[0, 2] == 'BM' then :bmp
|
84
|
+
when head[0, 3] =~ /P[1-6]\s|P7\n/ then detect_pnm_type(ir)
|
85
|
+
when head =~ /\#define\s+\S+\s+\d+/ then :xbm
|
86
|
+
when %W[II*\0 MM\0*].include?(head[0, 4]) then :tiff
|
87
|
+
when head =~ %r{/\* XPM \*/} then :xpm
|
88
|
+
when head[0, 4] == '8BPS' then :psd
|
89
|
+
when head[0, 3] =~ /[FC]WS/ then :swf
|
90
|
+
when head =~ SVG_R || (head =~ XML_R && ir[0, 4096] =~ SVG_R) then :svg
|
91
|
+
when head[0, 2] =~ /\n[\0-\5]/ then :pcx
|
92
|
+
when head[0, 12] =~ /RIFF(?m:....)WEBP/ then :webp
|
93
|
+
when head[0, 4] == "\0\0\1\0" then :ico
|
94
|
+
when head[0, 4] == "\0\0\2\0" then :cur
|
95
|
+
when head[0, 12] == "\0\0\0\fjP \r\n\207\n" then detect_jpeg2000_type(ir)
|
96
|
+
when head[0, 4] == "\377O\377Q" then :j2c
|
109
97
|
end
|
110
98
|
end
|
111
99
|
|
@@ -116,14 +104,34 @@ private
|
|
116
104
|
break if ['IDAT', 'IEND', nil].include?(type)
|
117
105
|
return :apng if type == 'acTL'
|
118
106
|
|
119
|
-
length = ir
|
107
|
+
length = ir.unpack1(offset, 4, 'N')
|
120
108
|
offset += 8 + length + 4
|
121
109
|
end
|
122
110
|
:png
|
123
111
|
end
|
124
112
|
|
113
|
+
def detect_pnm_type(ir)
|
114
|
+
case ir[0, 2]
|
115
|
+
when 'P1', 'P4' then :pbm
|
116
|
+
when 'P2', 'P5' then :pgm
|
117
|
+
when 'P3', 'P6' then :ppm
|
118
|
+
when 'P7' then :pam
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def detect_jpeg2000_type(ir)
|
123
|
+
return unless ir[16, 4] == 'ftyp'
|
124
|
+
|
125
|
+
# using xl-box would be weird, but doesn't seem to contradict specification
|
126
|
+
skip = ir[12, 4] == "\0\0\0\1" ? 16 : 8
|
127
|
+
case ir[12 + skip, 4]
|
128
|
+
when 'jp2 ' then :jp2
|
129
|
+
when 'jpx ' then :jpx
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
125
133
|
def size_of_gif(ir)
|
126
|
-
ir
|
134
|
+
ir.unpack(6, 4, 'vv')
|
127
135
|
end
|
128
136
|
|
129
137
|
def size_of_mng(ir)
|
@@ -131,7 +139,7 @@ private
|
|
131
139
|
raise FormatError, 'MHDR not in place for MNG'
|
132
140
|
end
|
133
141
|
|
134
|
-
ir
|
142
|
+
ir.unpack(16, 8, 'NN')
|
135
143
|
end
|
136
144
|
|
137
145
|
def size_of_png(ir)
|
@@ -139,15 +147,15 @@ private
|
|
139
147
|
raise FormatError, 'IHDR not in place for PNG'
|
140
148
|
end
|
141
149
|
|
142
|
-
ir
|
150
|
+
ir.unpack(16, 8, 'NN')
|
143
151
|
end
|
144
152
|
alias_method :size_of_apng, :size_of_png
|
145
153
|
|
146
|
-
JPEG_CODE_CHECK =
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
154
|
+
JPEG_CODE_CHECK = [
|
155
|
+
0xC0, 0xC1, 0xC2, 0xC3,
|
156
|
+
0xC5, 0xC6, 0xC7,
|
157
|
+
0xC9, 0xCA, 0xCB,
|
158
|
+
0xCD, 0xCE, 0xCF
|
151
159
|
].freeze
|
152
160
|
def size_of_jpeg(ir)
|
153
161
|
section_marker = "\xFF"
|
@@ -157,11 +165,11 @@ private
|
|
157
165
|
offset += 1 until section_marker != ir[offset + 1, 1]
|
158
166
|
raise FormatError, 'EOF in JPEG' if ir[offset, 1].nil?
|
159
167
|
|
160
|
-
|
168
|
+
code, length = ir.unpack(offset, 4, 'xCn')
|
161
169
|
offset += 4
|
162
170
|
|
163
171
|
if JPEG_CODE_CHECK.include?(code)
|
164
|
-
return ir
|
172
|
+
return ir.unpack(offset + 1, 4, 'nn').reverse
|
165
173
|
end
|
166
174
|
|
167
175
|
offset += length - 2
|
@@ -169,11 +177,11 @@ private
|
|
169
177
|
end
|
170
178
|
|
171
179
|
def size_of_bmp(ir)
|
172
|
-
header_size = ir
|
180
|
+
header_size = ir.unpack1(14, 4, 'V')
|
173
181
|
if header_size == 12
|
174
|
-
ir
|
182
|
+
ir.unpack(18, 4, 'vv')
|
175
183
|
else
|
176
|
-
ir
|
184
|
+
ir.unpack(18, 8, 'VV').map do |n|
|
177
185
|
if n > 0x7fff_ffff
|
178
186
|
0x1_0000_0000 - n # absolute value of converted to signed
|
179
187
|
else
|
@@ -187,12 +195,37 @@ private
|
|
187
195
|
header = ir[0, 1024]
|
188
196
|
header.gsub!(/^\#[^\n\r]*/m, '')
|
189
197
|
header =~ /^(P[1-6])\s+?(\d+)\s+?(\d+)/m
|
190
|
-
case $1
|
191
|
-
when 'P1', 'P4' then @format = :pbm
|
192
|
-
when 'P2', 'P5' then @format = :pgm
|
193
|
-
end
|
194
198
|
[$2.to_i, $3.to_i]
|
195
199
|
end
|
200
|
+
alias_method :size_of_pbm, :size_of_ppm
|
201
|
+
alias_method :size_of_pgm, :size_of_ppm
|
202
|
+
|
203
|
+
def size_of_pam(ir)
|
204
|
+
width = height = nil
|
205
|
+
offset = 3
|
206
|
+
until width && height
|
207
|
+
if ir[offset, 1] == '#'
|
208
|
+
offset += 1 until ["\n", '', nil].include?(ir[offset, 1])
|
209
|
+
offset += 1
|
210
|
+
else
|
211
|
+
chunk = ir[offset, 32]
|
212
|
+
case chunk
|
213
|
+
when /\AWIDTH (\d+)\n/
|
214
|
+
width = $1.to_i
|
215
|
+
when /\AHEIGHT (\d+)\n/
|
216
|
+
height = $1.to_i
|
217
|
+
when /\AENDHDR\n/
|
218
|
+
break
|
219
|
+
when /\A(?:DEPTH|MAXVAL) \d+\n/, /\ATUPLTYPE \S+\n/
|
220
|
+
# ignore
|
221
|
+
else
|
222
|
+
raise FormatError, "Unexpected data in PAM header: #{chunk.inspect}"
|
223
|
+
end
|
224
|
+
offset += $&.length
|
225
|
+
end
|
226
|
+
end
|
227
|
+
[width, height]
|
228
|
+
end
|
196
229
|
|
197
230
|
def size_of_xbm(ir)
|
198
231
|
ir[0, 1024] =~ /^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)/mi
|
@@ -212,23 +245,23 @@ private
|
|
212
245
|
end
|
213
246
|
|
214
247
|
def size_of_psd(ir)
|
215
|
-
ir
|
248
|
+
ir.unpack(14, 8, 'NN').reverse
|
216
249
|
end
|
217
250
|
|
218
251
|
def size_of_tiff(ir)
|
219
|
-
endian2b = ir
|
252
|
+
endian2b = ir.fetch(0, 4) == "II*\000" ? 'v' : 'n'
|
220
253
|
endian4b = endian2b.upcase
|
221
254
|
packspec = [nil, 'C', nil, endian2b, endian4b, nil, 'c', nil, endian2b, endian4b]
|
222
255
|
|
223
|
-
offset = ir
|
224
|
-
num_dirent = ir
|
256
|
+
offset = ir.unpack1(4, 4, endian4b)
|
257
|
+
num_dirent = ir.unpack1(offset, 2, endian2b)
|
225
258
|
offset += 2
|
226
259
|
num_dirent = offset + (num_dirent * 12)
|
227
260
|
|
228
261
|
width = height = nil
|
229
262
|
until width && height
|
230
|
-
ifd = ir
|
231
|
-
raise FormatError, 'Reached end of directory entries in TIFF' if
|
263
|
+
ifd = ir.fetch(offset, 12)
|
264
|
+
raise FormatError, 'Reached end of directory entries in TIFF' if offset > num_dirent
|
232
265
|
|
233
266
|
tag, type = ifd.unpack(endian2b * 2)
|
234
267
|
offset += 12
|
@@ -247,22 +280,23 @@ private
|
|
247
280
|
end
|
248
281
|
|
249
282
|
def size_of_pcx(ir)
|
250
|
-
parts = ir
|
283
|
+
parts = ir.unpack(4, 8, 'v4')
|
251
284
|
[parts[2] - parts[0] + 1, parts[3] - parts[1] + 1]
|
252
285
|
end
|
253
286
|
|
254
287
|
def size_of_swf(ir)
|
255
|
-
value_bit_length = ir
|
256
|
-
bit_length = 5 + value_bit_length * 4
|
257
|
-
rect_bits = ir
|
258
|
-
values = rect_bits.unpack(
|
288
|
+
value_bit_length = ir.unpack1(8, 1, 'B5').to_i(2)
|
289
|
+
bit_length = 5 + (value_bit_length * 4)
|
290
|
+
rect_bits = ir.unpack1(8, (bit_length / 8) + 1, "B#{bit_length}")
|
291
|
+
values = rect_bits[5..-1].unpack("a#{value_bit_length}" * 4).map{ |bits| bits.to_i(2) }
|
259
292
|
x_min, x_max, y_min, y_max = values
|
260
293
|
[(x_max - x_min) / 20, (y_max - y_min) / 20]
|
261
294
|
end
|
262
295
|
|
263
296
|
def size_of_svg(ir)
|
264
297
|
attributes = {}
|
265
|
-
ir
|
298
|
+
svg_tag = ir[0, 1024][SVG_R, 1] || ir[0, 4096][SVG_R, 1]
|
299
|
+
svg_tag.scan(/(\S+)=(?:'([^']*)'|"([^"]*)"|([^'"\s]*))/) do |name, v0, v1, v2|
|
266
300
|
attributes[name] = v0 || v1 || v2
|
267
301
|
end
|
268
302
|
dpi = self.class.dpi
|
@@ -283,20 +317,60 @@ private
|
|
283
317
|
end
|
284
318
|
|
285
319
|
def size_of_ico(ir)
|
286
|
-
ir
|
320
|
+
ir.unpack(6, 2, 'CC').map{ |v| v.zero? ? 256 : v }
|
287
321
|
end
|
288
322
|
alias_method :size_of_cur, :size_of_ico
|
289
323
|
|
290
324
|
def size_of_webp(ir)
|
291
|
-
case ir
|
325
|
+
case ir.fetch(12, 4)
|
292
326
|
when 'VP8 '
|
293
|
-
ir
|
327
|
+
ir.unpack(26, 4, 'vv').map{ |v| v & 0x3fff }
|
294
328
|
when 'VP8L'
|
295
|
-
n = ir
|
296
|
-
[(n & 0x3fff) + 1, (n >> 14 & 0x3fff) + 1]
|
329
|
+
n = ir.unpack1(21, 4, 'V')
|
330
|
+
[(n & 0x3fff) + 1, ((n >> 14) & 0x3fff) + 1]
|
297
331
|
when 'VP8X'
|
298
|
-
w16, w8, h16, h8 = ir
|
299
|
-
[(w16 | w8 << 16) + 1, (h16 | h8 << 16) + 1]
|
332
|
+
w16, w8, h16, h8 = ir.unpack(24, 6, 'vCvC')
|
333
|
+
[(w16 | (w8 << 16)) + 1, (h16 | (h8 << 16)) + 1]
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
def size_of_jp2(ir)
|
338
|
+
offset = 12
|
339
|
+
stop = nil
|
340
|
+
in_header = false
|
341
|
+
loop do
|
342
|
+
break if stop && offset >= stop
|
343
|
+
break if ir[offset, 4] == '' || ir[offset, 4].nil?
|
344
|
+
|
345
|
+
size = ir.unpack1(offset, 4, 'N')
|
346
|
+
type = ir.fetch(offset + 4, 4)
|
347
|
+
|
348
|
+
data_offset = 8
|
349
|
+
case size
|
350
|
+
when 1
|
351
|
+
size = ir.unpack1(offset, 8, 'Q>')
|
352
|
+
data_offset = 16
|
353
|
+
raise FormatError, "Unexpected xl-box size #{size}" if (1..15).include?(size)
|
354
|
+
when 2..7
|
355
|
+
raise FormatError, "Reserved box size #{size}"
|
356
|
+
end
|
357
|
+
|
358
|
+
if type == 'jp2h'
|
359
|
+
stop = offset + size unless size.zero?
|
360
|
+
offset += data_offset
|
361
|
+
in_header = true
|
362
|
+
elsif in_header && type == 'ihdr'
|
363
|
+
return ir.unpack(offset + data_offset, 8, 'NN').reverse
|
364
|
+
else
|
365
|
+
break if size.zero? # box to the end of file
|
366
|
+
|
367
|
+
offset += size
|
368
|
+
end
|
300
369
|
end
|
301
370
|
end
|
371
|
+
alias_method :size_of_jpx, :size_of_jp2
|
372
|
+
|
373
|
+
def size_of_j2c(ir)
|
374
|
+
ir.unpack(8, 8, 'NN')
|
375
|
+
end
|
302
376
|
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
|
data/spec/image_size_spec.rb
CHANGED
@@ -1,11 +1,38 @@
|
|
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
|
-
|
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://localhost:#{@server.config[:Port]}/")
|
23
|
+
end
|
24
|
+
|
25
|
+
after :all do
|
26
|
+
@server.shutdown
|
27
|
+
@server_thread.join
|
28
|
+
end
|
29
|
+
|
30
|
+
max_filesize = 16_384
|
31
|
+
|
32
|
+
(Dir['spec/images/*/*.*'] + [__FILE__[%r{spec/.+?\z}]]).each do |path|
|
33
|
+
filesize = File.size(path)
|
34
|
+
warn "#{path} is too big #{filesize} (max #{max_filesize})" if filesize > max_filesize
|
35
|
+
|
9
36
|
describe "for #{path}" do
|
10
37
|
let(:name){ File.basename(path) }
|
11
38
|
let(:attributes) do
|
@@ -45,13 +72,22 @@ describe ImageSize do
|
|
45
72
|
end
|
46
73
|
end
|
47
74
|
|
75
|
+
context 'given as unseekable IO' do
|
76
|
+
it 'gets format and dimensions' do
|
77
|
+
IO.popen(%W[cat #{path}].shelljoin, 'rb') do |io|
|
78
|
+
image_size = ImageSize.new(io)
|
79
|
+
expect(image_size).to have_attributes(attributes)
|
80
|
+
expect(io).not_to be_closed
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
48
85
|
context 'given as StringIO' do
|
49
86
|
it 'gets format and dimensions' do
|
50
87
|
io = StringIO.new(file_data)
|
51
88
|
image_size = ImageSize.new(io)
|
52
89
|
expect(image_size).to have_attributes(attributes)
|
53
90
|
expect(io).not_to be_closed
|
54
|
-
expect(io.pos).to_not be_zero
|
55
91
|
io.rewind
|
56
92
|
expect(io.read).to eq(file_data)
|
57
93
|
end
|
@@ -79,6 +115,13 @@ describe ImageSize do
|
|
79
115
|
expect(image_size).to have_attributes(attributes)
|
80
116
|
end
|
81
117
|
end
|
118
|
+
|
119
|
+
context 'fetching from webserver' do
|
120
|
+
it 'gets format and dimensions' do
|
121
|
+
image_size = ImageSize.url(@server_base_url + path)
|
122
|
+
expect(image_size).to have_attributes(attributes)
|
123
|
+
end
|
124
|
+
end
|
82
125
|
end
|
83
126
|
end
|
84
127
|
|
@@ -0,0 +1 @@
|
|
1
|
+
* -text
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
P7
|
2
|
+
WIDTH 22
|
3
|
+
HEIGHT 25
|
4
|
+
DEPTH 3
|
5
|
+
MAXVAL 255
|
6
|
+
TUPLTYPE RGB
|
7
|
+
ENDHDR
|
8
|
+
JMRGJONQVKNSRVZY^b{��|��osyz����Ǎ��v|�������UY_ORT�^_�ts�_b`FH�`aDGLHJPJMQfjnflplqu}�����u{�������nsw[`d]bgqv}aej>AFLLO�`c�ro�bdxORlsvZ_ccknS[^imrwz��������������ɑ��UY]���u{~��glosz~X^b�_^�li�lk���dimORWORWRUZY\a������������������UW\������]`ehmqOPU>AHfOR�lj�kjv}�KNSKOREILEIMTX[LQUAEJHJOZ]a_di���muz������=<BSUZrv|���}pt�jh�liPWZGJOIMPEILDHK=AE`eiuz~������}��������������XZ_MMR[^e�������ed�heHKPPSWFKNAFIMRV`hk���������nuxW\`V[_CHLu|����[^dBBGDHMBEJomr�hf�geJMSZ\aDILekn������dimPUYMNSBBGCDIFGLDEJ]`f���chlDGLT\^EMQ]MQ�ji�ecoehXadJMR���Y]a_afcdjORWKNTMTYJNRFFICCG]`d���z�==BFGLAEK�VX�ki�ec�nrLQWNSZdjmkqtBBHABGPX]^ltScgIMPCDHJJNQTX�����JKPPSX_^d�__�jf�ca�st�_bjX[jsw���^eh=@EIPUQX^RW\UY]JNR@AEegn���v{FFLmuy�]_�ec�gd�ca�zx�zx�po�cg~����y��YZ^CEIEGKSUZejnMRUZ]b���osxADIm[_�_`�ca�ec�db�st�|}�zy�vt�gh�ot�����Ϣ��ehlEGLX]`PRVX[_���dek7<@�RT�b_�a_�`^�ca�ux�{~�|z�yv�{w�rp�ii�����������ntwDDIgjn���`cjSSW�^^�gd�b`�`^�b`�yv�wx�xu�|x�yu�vs�vs�oo�ii�km������FHMimq���QX_x`d�fe�fb�da�b`�ca�wu�rp�vt�us�tr�vs�ts�sr�po�uv�ml�x|V[_gin���OU[�Z\�fc�ea�db�ca�b`�zx�tq�vt�us�wt�vs�wt�sq�rr�st�sq�giTX\SVZ���fbg�ce�eb�ca�ec�db�ec�yu�ur�sq�sr�vs�xu�xs�tq�xt�ws�xt�ihKMRchm���]NP�ge�eb�ca�db�ec�fd�zv�sq�rq�sr�rp�xu�so�rp�tq�qn�uq�bcHIN\bgo|�wQU�jh�fd�ca�b`�ca�ec�zy�xt�tr�vs�sr�sr�tq�sp�rp�kj�mk�^^HLPLOTfqv�UV�jf�ec�db�b`�cb�ca�ss�{w�us�tr�ur�wt�tq�qo�ro�lj�on�ZZ=BFNNTRZ_�YY�ie�db�db�`_�_^�`_�ij�~|�vs�ur�sq�pn�qo�ol�ji�mj�qn�Z]CFL]_dLIN�aa�fb�ca�cb�a`�__�]^x_^�{x�ws�wt�sp�pn�po�lknZ^�lk�pmxXYDINkrwkUX�mj�db�fdX[�Y\�`_�]]�gi�vs�us�xu�tr�nk�lj�nk�jj�mk�kjlPR?CGGIP�bb�pm�fd�da�Y\�]]�b_�`_�ru�ml�ur�wu�tr�pk�lg�oi�oj�pl�kiaMO;@EPGI�kj�he�fd�fc�b`�a^�b`�_^
|
Binary file
|
@@ -0,0 +1,4 @@
|
|
1
|
+
P5
|
2
|
+
22 25
|
3
|
+
255
|
4
|
+
MJQNU]��sÑ{��YRh�mLmGJMikp��z��r_aueALi�rXr^jZmz����ŗX�z�ky]k��hRRU\������W��`lPAT~|NNHHWPEJ]c�t��=Uv�s|VJLHG@dy�������ZM^��v|KSJEQg���t[ZG{�^BHEnx{M\Hj��hTNBDGE`�gGZLQ}yg_M�\adRNSMFC`�~=GE_yzPRipBBWj`LDJT��KS_n~w�i\q�d@OWVXMAg�zFtgz{w���j��ZEGUiQ]�sD_rwyx|���ss�ͩhG\R[�e;]wutw������u����sDj�cSm{vtv��������{w��Hl�We{zxvw����������~{Zi�Te{yxwv�����������qWV�ctywyxy�����������rMg�Qzywxyz�����������lIazY~zwvwy���������~�gKOo_yxvww~���������cANYe~xxutup�������w�cF_Jq{wxvtsd������x_�_HqZ�xzahvrm�����{�~VBIl�zweowu{{�������~Q?I||zzwuvt
|
@@ -0,0 +1,4 @@
|
|
1
|
+
P6
|
2
|
+
22 25
|
3
|
+
255
|
4
|
+
JMRGJONQVKNSRVZY^b{��|��osyz����Ǎ��v|�������UY_ORT�^_�ts�_b`FH�`aDGLHJPJMQfjnflplqu}�����u{�������nsw[`d]bgqv}aej>AFLLO�`c�ro�bdxORlsvZ_ccknS[^imrwz��������������ɑ��UY]���u{~��glosz~X^b�_^�li�lk���dimORWORWRUZY\a������������������UW\������]`ehmqOPU>AHfOR�lj�kjv}�KNSKOREILEIMTX[LQUAEJHJOZ]a_di���muz������=<BSUZrv|���}pt�jh�liPWZGJOIMPEILDHK=AE`eiuz~������}��������������XZ_MMR[^e�������ed�heHKPPSWFKNAFIMRV`hk���������nuxW\`V[_CHLu|����[^dBBGDHMBEJomr�hf�geJMSZ\aDILekn������dimPUYMNSBBGCDIFGLDEJ]`f���chlDGLT\^EMQ]MQ�ji�ecoehXadJMR���Y]a_afcdjORWKNTMTYJNRFFICCG]`d���z�==BFGLAEK�VX�ki�ec�nrLQWNSZdjmkqtBBHABGPX]^ltScgIMPCDHJJNQTX�����JKPPSX_^d�__�jf�ca�st�_bjX[jsw���^eh=@EIPUQX^RW\UY]JNR@AEegn���v{FFLmuy�]_�ec�gd�ca�zx�zx�po�cg~����y��YZ^CEIEGKSUZejnMRUZ]b���osxADIm[_�_`�ca�ec�db�st�|}�zy�vt�gh�ot�����Ϣ��ehlEGLX]`PRVX[_���dek7<@�RT�b_�a_�`^�ca�ux�{~�|z�yv�{w�rp�ii�����������ntwDDIgjn���`cjSSW�^^�gd�b`�`^�b`�yv�wx�xu�|x�yu�vs�vs�oo�ii�km������FHMimq���QX_x`d�fe�fb�da�b`�ca�wu�rp�vt�us�tr�vs�ts�sr�po�uv�ml�x|V[_gin���OU[�Z\�fc�ea�db�ca�b`�zx�tq�vt�us�wt�vs�wt�sq�rr�st�sq�giTX\SVZ���fbg�ce�eb�ca�ec�db�ec�yu�ur�sq�sr�vs�xu�xs�tq�xt�ws�xt�ihKMRchm���]NP�ge�eb�ca�db�ec�fd�zv�sq�rq�sr�rp�xu�so�rp�tq�qn�uq�bcHIN\bgo|�wQU�jh�fd�ca�b`�ca�ec�zy�xt�tr�vs�sr�sr�tq�sp�rp�kj�mk�^^HLPLOTfqv�UV�jf�ec�db�b`�cb�ca�ss�{w�us�tr�ur�wt�tq�qo�ro�lj�on�ZZ=BFNNTRZ_�YY�ie�db�db�`_�_^�`_�ij�~|�vs�ur�sq�pn�qo�ol�ji�mj�qn�Z]CFL]_dLIN�aa�fb�ca�cb�a`�__�]^x_^�{x�ws�wt�sp�pn�po�lknZ^�lk�pmxXYDINkrwkUX�mj�db�fdX[�Y\�`_�]]�gi�vs�us�xu�tr�nk�lj�nk�jj�mk�kjlPR?CGGIP�bb�pm�fd�da�Y\�]]�b_�`_�ru�ml�ur�wu�tr�pk�lg�oi�oj�pl�kiaMO;@EPGI�kj�he�fd�fc�b`�a^�b`�_^
|
@@ -0,0 +1,27 @@
|
|
1
|
+
P1
|
2
|
+
22 25
|
3
|
+
1 1 1 1 1 1 1 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1
|
4
|
+
1 1 1 1 1 1 0 0 1 0 0 0 0 1 0 1 1 1 1 1 1 1
|
5
|
+
1 1 1 1 1 1 0 0 0 0 0 0 1 0 1 0 1 1 1 1 1 0
|
6
|
+
1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 1 1 1 1 1 0 1
|
7
|
+
1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 1 1 1 1 1 1 0
|
8
|
+
1 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 0 0 1 1
|
9
|
+
1 1 1 1 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 1 0 1
|
10
|
+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0
|
11
|
+
1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1
|
12
|
+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1
|
13
|
+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 0 0 0
|
14
|
+
0 1 0 1 1 0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1
|
15
|
+
1 0 0 0 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 1 0 1
|
16
|
+
0 0 1 0 0 0 1 0 0 0 1 1 1 1 0 1 1 1 1 1 1 1
|
17
|
+
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 1 1 0 1 1 0
|
18
|
+
0 0 1 0 1 0 0 0 1 0 1 1 1 1 0 1 1 0 1 0 1 1
|
19
|
+
1 0 0 1 0 1 0 0 1 0 0 1 1 1 0 1 1 1 0 1 1 0
|
20
|
+
0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 0 1 0 0 1
|
21
|
+
1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1
|
22
|
+
0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 1 1 0 0 1 1 1
|
23
|
+
1 0 0 1 1 0 1 0 0 1 0 1 1 1 1 1 1 0 0 1 1 1
|
24
|
+
1 0 0 0 0 0 0 1 0 1 1 1 1 1 1 1 0 1 1 1 0 1
|
25
|
+
1 0 0 0 0 1 0 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1
|
26
|
+
1 0 1 0 0 0 1 0 1 1 1 1 1 1 1 1 0 1 1 1 0 0
|
27
|
+
1 0 0 1 0 0 1 0 1 0 1 1 1 1 1 1 1 1 0 1 1 0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
P2
|
2
|
+
22 25
|
3
|
+
255
|
4
|
+
77 74 81 78 85 93 129 129 115 127 195 145 123 169 147 89 82 104 135 109 76 109
|
5
|
+
71 74 77 105 107 112 132 169 122 151 204 114 95 97 117 101 65 76 105 133 114 88
|
6
|
+
114 94 106 90 109 122 165 164 178 187 197 151 88 134 122 130 107 121 93 107 128 127
|
7
|
+
158 104 82 82 85 92 144 155 154 180 157 183 87 182 145 96 108 80 65 84 127 126
|
8
|
+
124 78 78 72 72 87 80 69 74 93 99 157 116 160 139 61 85 118 141 115 124 127
|
9
|
+
86 74 76 72 71 64 100 121 139 170 132 142 154 182 160 90 77 94 142 145 118 124
|
10
|
+
75 83 74 69 81 103 137 170 158 116 91 90 71 123 173 94 66 72 69 110 120 123
|
11
|
+
77 92 72 106 138 140 104 84 78 66 68 71 69 96 161 103 71 90 76 81 125 121
|
12
|
+
103 95 77 134 92 97 100 82 78 83 77 70 67 96 185 126 61 71 69 95 127 121
|
13
|
+
122 80 82 105 112 66 66 87 106 96 76 68 74 84 180 130 75 83 95 110 126 119
|
14
|
+
131 105 92 113 140 100 64 79 87 86 88 77 65 103 189 122 70 116 103 122 123 119
|
15
|
+
138 138 128 106 127 158 128 90 69 71 85 105 81 93 191 115 68 95 114 119 121 120
|
16
|
+
124 142 140 137 115 115 168 205 169 104 71 92 82 91 185 101 59 93 119 117 116 119
|
17
|
+
131 140 140 138 140 131 117 132 146 166 148 115 68 106 192 99 83 109 123 118 116 118
|
18
|
+
138 137 137 140 138 135 136 129 123 119 138 140 72 108 178 87 101 123 122 120 118 119
|
19
|
+
136 132 136 135 134 135 134 134 128 133 126 123 90 105 177 84 101 123 121 120 119 118
|
20
|
+
138 134 136 135 136 135 136 133 131 132 134 113 87 86 163 99 116 121 119 121 120 121
|
21
|
+
137 134 133 133 135 137 137 134 137 136 138 114 77 103 147 81 122 121 119 120 121 122
|
22
|
+
139 133 132 132 129 137 132 132 134 131 135 108 73 97 122 89 126 122 119 118 119 121
|
23
|
+
137 137 134 135 133 133 134 133 132 126 129 103 75 79 111 95 127 121 120 118 119 119
|
24
|
+
126 140 135 134 134 136 134 131 133 127 131 99 65 78 89 101 126 120 120 117 116 117
|
25
|
+
112 143 135 134 133 130 132 129 119 127 133 99 70 95 74 113 123 119 120 118 116 115
|
26
|
+
100 139 136 136 133 131 132 120 95 127 132 95 72 113 90 128 120 122 97 104 118 114
|
27
|
+
109 133 135 137 134 128 127 127 123 128 126 86 66 73 108 131 122 119 101 111 119 117
|
28
|
+
123 123 135 136 134 130 127 129 129 130 126 81 63 73 124 124 122 122 119 117 118 116
|