dimensions 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,7 +2,7 @@ Dimensions
2
2
  ==========
3
3
 
4
4
  Dimensions is a pure Ruby library for reading the width, height and
5
- rotation angle of GIF, PNG and JPEG images.
5
+ rotation angle of GIF, PNG, JPEG and TIFF images.
6
6
 
7
7
  Use the `dimensions`, `width` and `height` methods on the `Dimensions`
8
8
  module to measure image files:
@@ -65,6 +65,10 @@ end
65
65
 
66
66
  ### Version History
67
67
 
68
+ **1.2.0** (April 25, 2012)
69
+
70
+ * Added support for measuring the dimensions of TIFF images.
71
+
68
72
  **1.1.0** (April 1, 2012)
69
73
 
70
74
  * Fixed an issue where images with certain invalid orientation values
@@ -3,6 +3,8 @@ require 'dimensions/io'
3
3
  require 'dimensions/jpeg_scanner'
4
4
  require 'dimensions/reader'
5
5
  require 'dimensions/scanner'
6
+ require 'dimensions/tiff_scanner'
7
+ require 'dimensions/tiff_scanning'
6
8
  require 'dimensions/version'
7
9
 
8
10
  # Extends an IO object with the `Dimensions::IO` module, which adds
@@ -1,7 +1,11 @@
1
1
  require 'dimensions/scanner'
2
+ require 'dimensions/tiff_scanning'
2
3
 
3
4
  module Dimensions
4
5
  class ExifScanner < Scanner
6
+ include TiffScanning
7
+
8
+ ORIENTATION_TAG = 0x0112
5
9
  ORIENTATIONS = [
6
10
  :top_left,
7
11
  :top_right,
@@ -23,21 +27,9 @@ module Dimensions
23
27
  def scan
24
28
  scan_header
25
29
 
26
- offset = read_long + 6
27
- skip_to(offset)
28
-
29
- # Note: This only checks the first IFD for orientation entries,
30
- # which seems to work fine in my (limited) testing but might not
31
- # play out in practice.
32
- entry_count = read_short
33
- entry_count.times do |i|
34
- skip_to(offset + 2 + (12 * i))
35
- tag = read_short
36
-
37
- if tag == 0x0112 # orientation
38
- advance(6)
39
- value = read_short
40
-
30
+ scan_ifd do |tag|
31
+ if tag == ORIENTATION_TAG
32
+ value = read_integer_value
41
33
  if valid_orientation?(value)
42
34
  @orientation = ORIENTATIONS[value - 1]
43
35
  end
@@ -50,20 +42,5 @@ module Dimensions
50
42
  def valid_orientation?(value)
51
43
  (1..ORIENTATIONS.length).include?(value)
52
44
  end
53
-
54
- def scan_header
55
- advance(6)
56
- scan_endianness
57
- scan_tag_mark
58
- end
59
-
60
- def scan_endianness
61
- tag = [read_char, read_char]
62
- @big = tag == [0x4D, 0x4D]
63
- end
64
-
65
- def scan_tag_mark
66
- raise ScanError unless read_short == 0x002A
67
- end
68
45
  end
69
46
  end
@@ -51,14 +51,14 @@ module Dimensions
51
51
  if length == (size * 3) + 8
52
52
  @width, @height = width, height
53
53
  else
54
- raise ScanError
54
+ raise_scan_error
55
55
  end
56
56
  end
57
57
 
58
58
  def scan_app1_frame
59
59
  frame = read_frame
60
60
  if frame[0..5] == "Exif\000\000"
61
- scanner = ExifScanner.new(frame)
61
+ scanner = ExifScanner.new(frame[6..-1])
62
62
  if scanner.scan
63
63
  case scanner.orientation
64
64
  when :bottom_right
@@ -2,9 +2,11 @@ require 'dimensions/jpeg_scanner'
2
2
 
3
3
  module Dimensions
4
4
  class Reader
5
- GIF_HEADER = [0x47, 0x49, 0x46, 0x38]
6
- PNG_HEADER = [0x89, 0x50, 0x4E, 0x47]
7
- JPEG_HEADER = [0xFF, 0xD8, 0xFF]
5
+ GIF_HEADER = [0x47, 0x49, 0x46, 0x38]
6
+ PNG_HEADER = [0x89, 0x50, 0x4E, 0x47]
7
+ JPEG_HEADER = [0xFF, 0xD8, 0xFF]
8
+ TIFF_HEADER_I = [0x49, 0x49, 0x2A, 0x00]
9
+ TIFF_HEADER_M = [0x4D, 0x4D, 0x00, 0x2A]
8
10
 
9
11
  attr_reader :type, :width, :height, :angle
10
12
 
@@ -41,6 +43,8 @@ module Dimensions
41
43
  @type = :png
42
44
  elsif match_header(JPEG_HEADER, bytes)
43
45
  @type = :jpeg
46
+ elsif match_header(TIFF_HEADER_I, bytes) || match_header(TIFF_HEADER_M, bytes)
47
+ @type = :tiff
44
48
  end
45
49
 
46
50
  process @type ? :"extract_#{type}_dimensions" : nil
@@ -77,6 +81,16 @@ module Dimensions
77
81
  rescue JpegScanner::ScanError
78
82
  end
79
83
 
84
+ def extract_tiff_dimensions
85
+ scanner = TiffScanner.new(@data)
86
+ if scanner.scan
87
+ @width = scanner.width
88
+ @height = scanner.height
89
+ process nil
90
+ end
91
+ rescue TiffScanner::ScanError
92
+ end
93
+
80
94
  def match_header(header, bytes)
81
95
  bytes[0, header.length] == header
82
96
  end
@@ -2,12 +2,14 @@ module Dimensions
2
2
  class Scanner
3
3
  class ScanError < ::StandardError; end
4
4
 
5
+ attr_reader :pos
6
+
5
7
  def initialize(data)
6
8
  @data = data.dup
7
9
  @data.force_encoding("BINARY") if @data.respond_to?(:force_encoding)
8
10
  @size = @data.length
9
11
  @pos = 0
10
- @big = true # endianness
12
+ big! # endianness
11
13
  end
12
14
 
13
15
  def read_char
@@ -35,12 +37,24 @@ module Dimensions
35
37
 
36
38
  def advance(length)
37
39
  @pos += length
38
- raise ScanError if @pos > @size
40
+ raise_scan_error if @pos > @size
39
41
  end
40
42
 
41
43
  def skip_to(pos)
42
44
  @pos = pos
43
- raise ScanError if @pos > @size
45
+ raise_scan_error if @pos > @size
46
+ end
47
+
48
+ def big!
49
+ @big = true
50
+ end
51
+
52
+ def little!
53
+ @big = false
54
+ end
55
+
56
+ def raise_scan_error
57
+ raise ScanError
44
58
  end
45
59
  end
46
60
  end
@@ -0,0 +1,33 @@
1
+ require 'dimensions/scanner'
2
+ require 'dimensions/tiff_scanning'
3
+
4
+ module Dimensions
5
+ class TiffScanner < Scanner
6
+ include TiffScanning
7
+
8
+ WIDTH_TAG = 0x100
9
+ HEIGHT_TAG = 0x101
10
+
11
+ attr_reader :width, :height
12
+
13
+ def initialize(data)
14
+ @width = nil
15
+ @height = nil
16
+ super
17
+ end
18
+
19
+ def scan
20
+ scan_header
21
+
22
+ scan_ifd do |tag|
23
+ if tag == WIDTH_TAG
24
+ @width = read_integer_value
25
+ elsif tag == HEIGHT_TAG
26
+ @height = read_integer_value
27
+ end
28
+ end
29
+
30
+ @width && @height
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ module Dimensions
2
+ module TiffScanning
3
+ def scan_header
4
+ scan_endianness
5
+ scan_tag_mark
6
+ scan_and_skip_to_offset
7
+ end
8
+
9
+ def scan_endianness
10
+ tag = [read_char, read_char]
11
+ tag == [0x4D, 0x4D] ? big! : little!
12
+ end
13
+
14
+ def scan_tag_mark
15
+ raise_scan_error unless read_short == 0x002A
16
+ end
17
+
18
+ def scan_and_skip_to_offset
19
+ offset = read_long
20
+ skip_to(offset)
21
+ end
22
+
23
+ def scan_ifd
24
+ offset = pos
25
+ entry_count = read_short
26
+
27
+ entry_count.times do |i|
28
+ skip_to(offset + 2 + (12 * i))
29
+ tag = read_short
30
+ yield tag
31
+ end
32
+ end
33
+
34
+ def read_integer_value
35
+ type = read_short
36
+ advance(4)
37
+
38
+ if type == 3
39
+ read_short
40
+ elsif type == 4
41
+ read_long
42
+ else
43
+ raise_scan_error
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Dimensions
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dimensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-01 00:00:00.000000000 Z
12
+ date: 2012-04-25 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A pure Ruby library for measuring the dimensions and rotation angles
15
- of GIF, PNG and JPEG images.
15
+ of GIF, PNG, JPEG and TIFF images.
16
16
  email:
17
17
  - sstephenson@gmail.com
18
18
  executables: []
@@ -26,6 +26,8 @@ files:
26
26
  - lib/dimensions/jpeg_scanner.rb
27
27
  - lib/dimensions/reader.rb
28
28
  - lib/dimensions/scanner.rb
29
+ - lib/dimensions/tiff_scanner.rb
30
+ - lib/dimensions/tiff_scanning.rb
29
31
  - lib/dimensions/version.rb
30
32
  - lib/dimensions.rb
31
33
  homepage: https://github.com/sstephenson/dimensions
@@ -51,5 +53,5 @@ rubyforge_project:
51
53
  rubygems_version: 1.8.11
52
54
  signing_key:
53
55
  specification_version: 3
54
- summary: Pure Ruby dimension measurement for GIF, PNG and JPEG images
56
+ summary: Pure Ruby dimension measurement for GIF, PNG, JPEG and TIFF images
55
57
  test_files: []