fastimage 1.4.0 → 1.5.0

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
  SHA1:
3
- metadata.gz: fc7eb99ff0f61cddf103ac901c5bda2d37f83752
4
- data.tar.gz: fccb0a33cfccefc1400c4d7c3c27a1124d2b6400
3
+ metadata.gz: af0ff2b0f792939e83294bbac7a348b5246f9021
4
+ data.tar.gz: 14737f78d877a431786c2e5bb437055a9dd01bdd
5
5
  SHA512:
6
- metadata.gz: 000bc8011c9da184973abc60e5b119fd5a8ef8b1d3657cd80dd26ae12c67298d1dcd73ad7d2ed60c783be8d4542f1f57228e6c0b888ebb313499739173c5ec7b
7
- data.tar.gz: fa02a8dfdaf54cc85e94fa468839b2c2fb718f35c4199959859109925f20c3fa63fcf6574fcce83c22a13cda94ccc4caed6f05eb82a907a635d4bc7f59c9fe55
6
+ metadata.gz: 1748c1570f833457b0c09ed075aa81b33bc702852ee23af7bab85118466e9b093584ae776bc30f0a846074e281e439e617eff544ed6cb3362aaa1f1922dd3c50
7
+ data.tar.gz: 2d31f722472a87b073a89413c301bce966dc30e8ff2f7926e276de39d0345facf5671b7fed373314df0aef7fa4e9caa76b8c86ca5c49ed5258beddde80762c2a
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2011 Stephen Sykes
1
+ Copyright (c) 2008-2013 Stephen Sykes
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.textile CHANGED
@@ -8,7 +8,7 @@ Your app needs to find the size or type of an image. This could be for adding w
8
8
 
9
9
  But the image is not locally stored - it's on another asset server, or in the cloud - at Amazon S3 for example.
10
10
 
11
- You don't want to download the entire image to your app server - it could be many tens of kilobytes, or even megabytes just to get this information. For most image types, the size of the image is simply stored at the start of the file. For JPEG files it's a little bit more complex, but even so you do not need to fetch much of the image to find the size.
11
+ You don't want to download the entire image to your app server - it could be many tens of kilobytes, or even megabytes just to get this information. For most common image types (GIF, PNG, BMP), the size of the image is simply stored at the start of the file. For JPEG files it's a little bit more complex, but even so you do not need to fetch much of the image to find the size.
12
12
 
13
13
  FastImage does this minimal fetch for image types GIF, JPEG, PNG, TIFF and BMP. And it doesn't rely on installing external libraries such as RMagick (which relies on ImageMagick or GraphicsMagick) or ImageScience (which relies on FreeImage).
14
14
 
@@ -54,18 +54,46 @@ bc. gem install fastimage
54
54
 
55
55
  h4. Rails
56
56
 
57
- Install the gem as above, and add it to your Gemfile if you are using bundler, or configure it in your environment.rb file as below:
58
- <pre lang="ruby"><code>
59
- Rails::Initializer.run do |config|
60
- config.gem "fastimage"
61
- end
62
- </code></pre>
57
+ Install the gem as above, and add it to your Gemfile.
58
+
63
59
  Then you're off - just use @FastImage.size()@ and @FastImage.type()@ in your code as in the examples.
64
60
 
65
61
  h2. Documentation
66
62
 
67
63
  "http://sdsykes.github.io/fastimage/rdoc/FastImage.html":http://sdsykes.github.io/fastimage/rdoc/FastImage.html
68
64
 
65
+ h2. Benchmark
66
+
67
+ It's way faster than conventional methods (for example the image_size gem) for most types of file when fetching over the wire.
68
+
69
+ <pre lang="ruby"><code>
70
+ irb> uri = "http://upload.wikimedia.org/wikipedia/commons/b/b4/Mardin_1350660_1350692_33_images.jpg"
71
+ irb> puts Benchmark.measure {open(uri, 'rb') {|fh| p ImageSize.new(fh).size}}
72
+ [9545, 6623]
73
+ 0.680000 0.250000 0.930000 ( 7.571887)
74
+
75
+ irb> puts Benchmark.measure {p FastImage.size(uri)}
76
+ [9545, 6623]
77
+ 0.010000 0.000000 0.010000 ( 0.090640)
78
+ </code></pre>
79
+
80
+ The file is fetched in about 7.5 seconds in this test (the number in brackets is the total time taken), but as FastImage doesn't need to fetch the whole thing, it completes in less than 0.1s.
81
+
82
+ You'll see similar excellent results for the other file types, except for TIFF. Unfortunately TIFFs tend to have their
83
+ metadata towards the end of the file, so it makes little difference to do a minimal fetch. The result shown below is
84
+ mostly dependent on the exact internet conditions during the test, and little to do with the library used.
85
+
86
+ <pre lang="ruby"><code>
87
+ irb> uri = "http://upload.wikimedia.org/wikipedia/commons/1/11/Shinbutsureijoushuincho.tiff"
88
+ irb> puts Benchmark.measure {open(uri, 'rb') {|fh| p ImageSize.new(fh).size}}
89
+ [1120, 1559]
90
+ 1.080000 0.370000 1.450000 ( 13.766962)
91
+
92
+ irb> puts Benchmark.measure {p FastImage.size(uri)}
93
+ [1120, 1559]
94
+ 3.490000 3.810000 7.300000 ( 11.754315)
95
+ </code></pre>
96
+
69
97
  h2. Tests
70
98
 
71
99
  You'll need to @gem install fakeweb@ to be able to run the tests.
data/lib/fastimage.rb CHANGED
@@ -173,6 +173,8 @@ class FastImage
173
173
  end
174
174
  end
175
175
 
176
+ uri.rewind if uri.respond_to?(:rewind)
177
+
176
178
  raise SizeNotFound if options[:raise_on_failure] && @property == :size && !@size
177
179
 
178
180
  rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET,
@@ -274,6 +276,7 @@ class FastImage
274
276
  @str.force_encoding("ASCII-8BIT") if has_encoding?
275
277
  @strpos = 0
276
278
  @bytes_read = 0
279
+ @bytes_delivered = 0
277
280
 
278
281
  begin
279
282
  result = send("parse_#{@property}")
@@ -290,6 +293,7 @@ class FastImage
290
293
  def parse_size
291
294
  @type = parse_type unless @type
292
295
  @strpos = 0
296
+ @bytes_delivered = 0
293
297
  send("parse_size_for_#{@type}")
294
298
  end
295
299
 
@@ -320,6 +324,7 @@ class FastImage
320
324
 
321
325
  result = @str[@strpos..(@strpos + n - 1)]
322
326
  @strpos += n
327
+ @bytes_delivered += n
323
328
  result
324
329
  end
325
330
 
@@ -369,6 +374,15 @@ class FastImage
369
374
  get_byte == 0xFF ? :sof : :started
370
375
  when :sof
371
376
  case get_byte
377
+ when 0xe1 # APP1
378
+ skip_chars = read_int(get_chars(2)) - 2
379
+ skip_from = @bytes_delivered
380
+ if get_chars(4) == "Exif"
381
+ get_chars(2)
382
+ parse_exif
383
+ end
384
+ get_chars(skip_chars - (@bytes_delivered - skip_from))
385
+ :started
372
386
  when 0xe0..0xef
373
387
  :skipframe
374
388
  when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF
@@ -379,14 +393,16 @@ class FastImage
379
393
  :skipframe
380
394
  end
381
395
  when :skipframe
382
- @skip_chars = read_int(get_chars(2)) - 2
383
- :do_skip
384
- when :do_skip
385
- get_chars(@skip_chars)
396
+ skip_chars = read_int(get_chars(2)) - 2
397
+ get_chars(skip_chars)
386
398
  :started
387
399
  when :readsize
388
400
  s = get_chars(7)
389
- return [read_int(s[5..6]), read_int(s[3..4])]
401
+ if @exif_orientation && @exif_orientation >= 5
402
+ return [read_int(s[3..4]), read_int(s[5..6])]
403
+ else
404
+ return [read_int(s[5..6]), read_int(s[3..4])]
405
+ end
390
406
  end
391
407
  end
392
408
  end
@@ -396,36 +412,67 @@ class FastImage
396
412
  d.unpack("C")[0] == 40 ? d[4..-1].unpack('LL') : d[4..8].unpack('SS')
397
413
  end
398
414
 
399
- def parse_size_for_tiff
415
+ def get_exif_byte_order
400
416
  byte_order = get_chars(2)
401
417
  case byte_order
402
- when 'II'; short, long = 'v', 'V'
403
- when 'MM'; short, long = 'n', 'N'
418
+ when 'II'
419
+ @short, @long = 'v', 'V'
420
+ when 'MM'
421
+ @short, @long = 'n', 'N'
422
+ else
423
+ raise CannotParseImage
404
424
  end
405
- get_chars(2) # 42
406
-
407
- offset = get_chars(4).unpack(long)[0]
408
- get_chars(offset - 8)
409
-
410
- width = height = nil
425
+ end
411
426
 
412
- tag_count = get_chars(2).unpack(short)[0]
427
+ def parse_exif_ifd
428
+ tag_count = get_chars(2).unpack(@short)[0]
413
429
  tag_count.downto(1) do
414
- type = get_chars(2).unpack(short)[0]
430
+ type = get_chars(2).unpack(@short)[0]
415
431
  get_chars(6)
416
- data = get_chars(2).unpack(short)[0]
432
+ data = get_chars(2).unpack(@short)[0]
417
433
  case type
418
434
  when 0x0100 # image width
419
- width = data
435
+ @exif_width = data
420
436
  when 0x0101 # image height
421
- height = data
437
+ @exif_height = data
438
+ when 0x0112 # orientation
439
+ @exif_orientation = data
422
440
  end
423
- if width && height
424
- return [width, height]
441
+ if @type == :tiff && @exif_width && @exif_height && @exif_orientation
442
+ return # no need to parse more
425
443
  end
426
444
  get_chars(2)
427
445
  end
446
+
447
+ next_offset = get_chars(4).unpack(@long)[0]
448
+ if next_offset > 0
449
+ get_chars(next_offset - (@bytes_delivered - @exif_start_byte))
450
+ parse_exif_ifd
451
+ end
452
+ end
453
+
454
+ def parse_exif
455
+ @exif_start_byte = @bytes_delivered
456
+
457
+ get_exif_byte_order
428
458
 
459
+ get_chars(2) # 42
460
+
461
+ offset = get_chars(4).unpack(@long)[0]
462
+ get_chars(offset - 8)
463
+
464
+ parse_exif_ifd
465
+ end
466
+
467
+ def parse_size_for_tiff
468
+ parse_exif
469
+
470
+ if @exif_orientation && @exif_orientation >= 5
471
+ return [@exif_height, @exif_width]
472
+ else
473
+ return [@exif_width, @exif_height]
474
+ end
475
+
429
476
  raise CannotParseImage
430
477
  end
431
478
  end
Binary file
data/test/test.rb CHANGED
@@ -18,7 +18,8 @@ GoodFixtures = {
18
18
  "test2.jpg"=>[:jpeg, [250, 188]],
19
19
  "test3.jpg"=>[:jpeg, [630, 367]],
20
20
  "test.tiff"=>[:tiff, [85, 67]],
21
- "test2.tiff"=>[:tiff, [333, 225]]
21
+ "test2.tiff"=>[:tiff, [333, 225]],
22
+ "exif_orientation.jpg"=>[:jpeg, [2448, 3264]]
22
23
  }
23
24
 
24
25
  BadFixtures = [
@@ -123,6 +124,15 @@ class FastImageTest < Test::Unit::TestCase
123
124
  end
124
125
  end
125
126
  end
127
+
128
+ def test_should_report_size_correctly_on_io_object_twice
129
+ GoodFixtures.each do |fn, info|
130
+ File.open(File.join(FixturePath, fn), "r") do |io|
131
+ assert_equal info[1], FastImage.size(io)
132
+ assert_equal info[1], FastImage.size(io)
133
+ end
134
+ end
135
+ end
126
136
 
127
137
  def test_should_report_size_correctly_for_local_files_with_path_that_has_spaces
128
138
  Dir.chdir(PathHere) do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastimage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Sykes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-08 00:00:00.000000000 Z
11
+ date: 2013-07-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: FastImage finds the size or type of an image given its uri by fetching
14
14
  as little as needed.
@@ -32,10 +32,12 @@ files:
32
32
  - test/fixtures/test3.jpg
33
33
  - test/fixtures/test.tiff
34
34
  - test/fixtures/test2.tiff
35
+ - test/fixtures/exif_orientation.jpg
35
36
  - test/fixtures/folder with spaces/test.bmp
36
37
  - test/test.rb
37
38
  homepage: http://github.com/sdsykes/fastimage
38
- licenses: []
39
+ licenses:
40
+ - MIT
39
41
  metadata: {}
40
42
  post_install_message:
41
43
  rdoc_options: