identify 0.1.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.
- data/CHANGELOG +4 -0
- data/README.md +36 -0
- data/lib/identify.rb +175 -0
- metadata +64 -0
data/CHANGELOG
ADDED
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Identify
|
2
|
+
|
3
|
+
A pure ruby image identification library.
|
4
|
+
|
5
|
+
## Supported Formats
|
6
|
+
|
7
|
+
* BMP
|
8
|
+
* PNG
|
9
|
+
* JPG
|
10
|
+
* GIF
|
11
|
+
* XPM
|
12
|
+
* PPM
|
13
|
+
* PGM
|
14
|
+
* PNM
|
15
|
+
* PBM
|
16
|
+
* XBM
|
17
|
+
* TIFF
|
18
|
+
|
19
|
+
## Example
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'identify'
|
23
|
+
|
24
|
+
Identify.image File.binread("test/images/test.png", 1024) #=> {:format => "png", :width => 253, :height => 178}
|
25
|
+
|
26
|
+
```
|
27
|
+
|
28
|
+
## Testing
|
29
|
+
|
30
|
+
Tests require a local installation of ImageMagick and `identify` to be in your `$PATH`
|
31
|
+
|
32
|
+
# See Also
|
33
|
+
[http://rubygems.org/gems/imagesize](http://rubygems.org/gems/imagesize)
|
34
|
+
|
35
|
+
# License
|
36
|
+
[Creative Commons Attribution - CC BY](http://creativecommons.org/licenses/by/3.0)
|
data/lib/identify.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
module Identify
|
2
|
+
VERSION = '0.1.0'
|
3
|
+
|
4
|
+
def self.image data
|
5
|
+
Image.identify(data)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Image
|
9
|
+
def self.formats
|
10
|
+
@formats ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.inherited klass
|
14
|
+
formats << klass
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.identify data
|
18
|
+
format = formats.find {|klass| klass.handle? data}
|
19
|
+
format ? format.parse(data) : {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse data
|
23
|
+
new.parse data
|
24
|
+
end
|
25
|
+
|
26
|
+
def as_hash format, width, height
|
27
|
+
{width: width.to_i, height: height.to_i, format: format}
|
28
|
+
end
|
29
|
+
|
30
|
+
class XPM < Image
|
31
|
+
def self.handle? data
|
32
|
+
%r{\A#{Regexp.escape('/* XPM */')}}.match(data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse data
|
36
|
+
as_hash 'xpm', *data.scan(%r{"(\d+)\s+(\d+)(?=[\s\d]+")}).flatten
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class PCX < Image
|
41
|
+
def self.handle? data
|
42
|
+
data[0].ord == 10
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse data
|
46
|
+
header = data.unpack('C4S4')
|
47
|
+
as_hash 'pcx', header[6] - header[4] + 1, header[7] - header[5] + 1
|
48
|
+
end
|
49
|
+
end # PCX
|
50
|
+
|
51
|
+
class TIFF < Image
|
52
|
+
def self.handle? data
|
53
|
+
data[0..3] == "MM\x00\x2a" || data[0..3] == "II\x2a\x00"
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse data
|
57
|
+
endian = data[0..1] == "MM" ? 'n' : 'v'
|
58
|
+
# IFD offset
|
59
|
+
offset = data.unpack("x4#{endian.upcase}").first
|
60
|
+
# Don't have enough header data
|
61
|
+
return {} if data.bytesize < offset + 14
|
62
|
+
|
63
|
+
nrec = data[offset, 2].unpack(endian).first
|
64
|
+
offset += 2
|
65
|
+
height = nil
|
66
|
+
width = nil
|
67
|
+
types = [nil, 'C', nil, endian, endian.upcase]
|
68
|
+
|
69
|
+
while nrec > 0 && data.bytesize > offset + 12
|
70
|
+
ifd = data[offset, 12]
|
71
|
+
type = ifd.unpack("x2#{endian}").first
|
72
|
+
case ifd.unpack(endian).first
|
73
|
+
when 0x0100
|
74
|
+
width = ifd[8, 4].unpack(types[type]).first
|
75
|
+
when 0x0101
|
76
|
+
height = ifd[8, 4].unpack(types[type]).first
|
77
|
+
end
|
78
|
+
nrec -= 1
|
79
|
+
offset += 12
|
80
|
+
|
81
|
+
break if width && height
|
82
|
+
end
|
83
|
+
as_hash 'tiff', width, height
|
84
|
+
end
|
85
|
+
end # TIFF
|
86
|
+
|
87
|
+
class BMP < Image
|
88
|
+
def self.handle? data
|
89
|
+
%r{\ABM}.match(data)
|
90
|
+
end
|
91
|
+
|
92
|
+
def parse data
|
93
|
+
as_hash 'bmp', *data.unpack("x18VV")
|
94
|
+
end
|
95
|
+
end # BMP
|
96
|
+
|
97
|
+
class PBM < Image
|
98
|
+
def self.handle? data
|
99
|
+
%r{\AP[1-6]}.match(data)
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse data
|
103
|
+
type, dims = data[0..4096].split(/\n+/).reject {|line| %r{\A#}.match(line)}.take(2)
|
104
|
+
as_hash format(type), *dims.split(/\s+/)
|
105
|
+
end
|
106
|
+
|
107
|
+
def format type
|
108
|
+
case type
|
109
|
+
when 'P1', 'P4' then 'pbm'
|
110
|
+
when 'P2', 'P5' then 'pgm'
|
111
|
+
when 'P3', 'P6' then 'ppm'
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end # PBM
|
115
|
+
|
116
|
+
class XBM < Image
|
117
|
+
def self.handle? data
|
118
|
+
%r{\A#define\s+.*width}i.match(data)
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse data
|
122
|
+
as_hash 'xbm', *data.scan(%r{^#define\s+.*?_(?:width|height)\s+(\d+)}).flatten
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class GIF < Image
|
127
|
+
def self.handle? data
|
128
|
+
data.index("GIF89a") == 0 || data.index("GIF87a")
|
129
|
+
end
|
130
|
+
|
131
|
+
def parse data
|
132
|
+
as_hash('gif', *data.unpack("x6vv"))
|
133
|
+
end
|
134
|
+
end # GIF
|
135
|
+
|
136
|
+
class PNG < Image
|
137
|
+
def self.handle? data
|
138
|
+
data[0..7] == "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A" # png 8-byte signature
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse data
|
142
|
+
{}.tap do |meta|
|
143
|
+
meta.merge! as_hash('png', *data.unpack("x16NN")) if data.index("IHDR") == 12
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end # PNG
|
147
|
+
|
148
|
+
class JFIF < Image
|
149
|
+
# http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#SOF
|
150
|
+
SOF = [0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf]
|
151
|
+
|
152
|
+
def self.handle? data
|
153
|
+
data.index("JFIF", 4) == 6
|
154
|
+
end
|
155
|
+
|
156
|
+
def parse data
|
157
|
+
index = 4
|
158
|
+
block = data[index].ord * 256 + data[index + 1].ord
|
159
|
+
|
160
|
+
{}.tap do |meta|
|
161
|
+
while (index += block) < data.size
|
162
|
+
break unless data[index].ord == 0xff
|
163
|
+
if SOF.include?(data[index + 1].ord)
|
164
|
+
meta.merge! as_hash('jpeg', *data.unpack("x#{index + 5}nn").reverse)
|
165
|
+
break
|
166
|
+
else
|
167
|
+
index += 2
|
168
|
+
block = data[index].ord * 256 + data[index + 1].ord
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end # JFIF
|
174
|
+
end # Image
|
175
|
+
end # Identify
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: identify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bharanee Rathna
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: Image identification in pure Ruby
|
31
|
+
email:
|
32
|
+
- deepfryed@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- lib/identify.rb
|
38
|
+
- README.md
|
39
|
+
- CHANGELOG
|
40
|
+
homepage: http://github.com/deepfryed/identify
|
41
|
+
licenses: []
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.24
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Identify image types and dimensions
|
64
|
+
test_files: []
|