ruby-imagespec-jp 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ # Copyright (c) 2008, Brandon Anderson (anderson.brandon@gmail.com)
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without modification,
5
+ # are permitted provided that the following conditions are met:
6
+ #
7
+ # Redistributions of source code must retain the above copyright notice,
8
+ # this list of conditions and the following disclaimer.
9
+ #
10
+ # Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # Neither the name of the original author nor the names of contributors
15
+ # may be used to endorse or promote products derived from this software
16
+ # without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ #
data/README ADDED
@@ -0,0 +1,30 @@
1
+ ImageSpec
2
+ =========
3
+
4
+ ImageSpec is a lightweight module designed to extract width/height dimensions from most standard image formats, as well as SWFs.
5
+
6
+ This is a work in progress. I intend on expanding this to include other details (EXIF, various metadata, etc.) as well.
7
+
8
+
9
+ Example
10
+ =======
11
+
12
+ # From a file in your file system
13
+ instance = ImageSpec.new('/path/to/your/file')
14
+
15
+ # From a URL
16
+ instance = ImageSpec.new('http://example.com/image.png')
17
+
18
+ # From an IO stream
19
+ file = File.new('/path/to/your/file', 'rb')
20
+ instance = ImageSpec.new(file)
21
+
22
+ instance.width
23
+ instance.height
24
+ instance.content_type
25
+
26
+ Pretty simple, huh?
27
+
28
+ Copyright (c) 2008-2011 Brandon Anderson, released under the MIT license
29
+
30
+ Contributions by Michael Sheakoski, Mike Boone and Dimitrij Denissenko
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the image_spec plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the image_spec plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'ImageSpec'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ begin
25
+ require 'jeweler'
26
+ Jeweler::Tasks.new do |gemspec|
27
+ gemspec.name = "ruby-imagespec"
28
+ gemspec.summary = "Image/Flash extract width/height dimensions extractor"
29
+ gemspec.description = "A lightweight module designed to extract the width/height dimensions of various image types. Also supports SWFs. Now supports version for SWFs."
30
+ gemspec.email = "dimitrij@blacksquaremedia.com"
31
+ gemspec.homepage = "http://github.com/dim/ruby-imagespec"
32
+ gemspec.authors = [
33
+ "Brandon Anderson",
34
+ "Michael Sheakoski",
35
+ "Mike Boone",
36
+ "Dimitrij Denissenko",
37
+ "Juan Pablo Lopez N."]
38
+ end
39
+ Jeweler::GemcutterTasks.new
40
+ rescue LoadError
41
+ puts "Jeweler not available. Install it with: gem install jeweler"
42
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'image_spec')
data/lib/image_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'open-uri'
2
+ require File.join(File.dirname(__FILE__), 'parser')
3
+
4
+ class ImageSpec
5
+
6
+ def initialize(file)
7
+ @attributes = Parser.parse(stream_for(file))
8
+
9
+ @attributes.each do |key, value|
10
+ instance_eval <<-RUBY, __FILE__, __LINE__ + 1
11
+ def #{key}
12
+ @attributes[:#{key}]
13
+ end
14
+ RUBY
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def stream_for(file)
21
+ if file.respond_to?(:read)
22
+ file
23
+ elsif file.is_a?(String)
24
+ open(file, 'rb')
25
+ else
26
+ raise "Unable to get stream for #{file.inspect}"
27
+ end
28
+ end
29
+
30
+ end
data/lib/parser/gif.rb ADDED
@@ -0,0 +1,28 @@
1
+ class ImageSpec
2
+
3
+ module Parser
4
+
5
+ class GIF
6
+
7
+ CONTENT_TYPE = 'image/gif'
8
+
9
+ def self.attributes(stream)
10
+ width, height = dimensions(stream)
11
+ {:width => width, :height => height, :content_type => CONTENT_TYPE}
12
+ end
13
+
14
+ def self.detected?(stream)
15
+ stream.rewind
16
+ stream.read(4) == 'GIF8'
17
+ end
18
+
19
+ def self.dimensions(stream)
20
+ stream.seek(6)
21
+ stream.read(4).unpack('SS')
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,69 @@
1
+ class ImageSpec
2
+
3
+ module Parser
4
+
5
+ class JPEG
6
+
7
+ CONTENT_TYPE = 'image/jpeg'
8
+
9
+ def self.attributes(stream)
10
+ width, height = dimensions(stream)
11
+ {:width => width, :height => height, :content_type => CONTENT_TYPE}
12
+ end
13
+
14
+ def self.detected?(stream)
15
+ stream.rewind
16
+ case stream.read(10)
17
+ when /^\xff\xd8\xff\xe0\x00\x10JFIF/ then true
18
+ when /^\xff\xd8\xff\xe1(.*){2}Exif/ then true
19
+ else false
20
+ end
21
+ end
22
+
23
+ def self.dimensions(stream)
24
+ stream.rewind
25
+ raise 'malformed JPEG' unless stream.getc == 0xFF && stream.getc == 0xD8 # SOI
26
+
27
+ class << stream
28
+ def readint
29
+ (readchar << 8) + readchar
30
+ end
31
+
32
+ def readframe
33
+ read(readint - 2)
34
+ end
35
+
36
+ def readsof
37
+ [readint, readchar, readint, readint, readchar]
38
+ end
39
+
40
+ def next
41
+ c = readchar while c != 0xFF
42
+ c = readchar while c == 0xFF
43
+ c
44
+ end
45
+ end
46
+
47
+ while marker = stream.next
48
+ case marker
49
+ when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF
50
+ length, bits, height, width, components = stream.readsof
51
+ raise 'malformed JPEG' unless length == 8 + components * 3
52
+ return [width, height]
53
+ when 0xD9, 0xDA
54
+ break
55
+ when 0xFE
56
+ @comment = stream.readframe
57
+ when 0xE1
58
+ stream.readframe
59
+ else
60
+ stream.readframe
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ end
data/lib/parser/png.rb ADDED
@@ -0,0 +1,28 @@
1
+ class ImageSpec
2
+
3
+ module Parser
4
+
5
+ class PNG
6
+
7
+ CONTENT_TYPE = 'image/png'
8
+
9
+ def self.attributes(stream)
10
+ width, height = dimensions(stream)
11
+ {:width => width, :height => height, :content_type => CONTENT_TYPE}
12
+ end
13
+
14
+ def self.detected?(stream)
15
+ stream.rewind
16
+ stream.read(4) == "\x89PNG"
17
+ end
18
+
19
+ def self.dimensions(stream)
20
+ stream.seek(0x10)
21
+ stream.read(8).unpack('NN')
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
data/lib/parser/swf.rb ADDED
@@ -0,0 +1,81 @@
1
+ require 'zlib'
2
+
3
+ class ImageSpec
4
+
5
+ module Parser
6
+
7
+ class SWF
8
+
9
+ CONTENT_TYPE = 'application/x-shockwave-flash'
10
+
11
+ def self.attributes(stream)
12
+ width, height, version = dimensions(stream)
13
+ {:width => width, :height => height, :content_type => CONTENT_TYPE, :version => version}
14
+ end
15
+
16
+ def self.detected?(stream)
17
+ stream.rewind
18
+ stream.read(3) =~ /(F|C)WS/ ? true : false
19
+ end
20
+
21
+ def self.dimensions(stream)
22
+ # Read the entire stream into memory because the
23
+ # dimensions aren't stored in a standard location
24
+ stream.rewind
25
+ contents = stream.read
26
+
27
+ # Our 'signature' is the first 3 bytes
28
+ # Either FWS or CWS. CWS indicates compression
29
+ signature = contents[0..2]
30
+
31
+ # SWF version
32
+ version = contents[3].unpack('C').join.to_i
33
+
34
+ # Determine the length of the uncompressed stream
35
+ length = contents[4..7].unpack('V').join.to_i
36
+
37
+ # If we do, in fact, have compression
38
+ if signature == 'CWS'
39
+ # Decompress the body of the SWF
40
+ body = Zlib::Inflate.inflate( contents[8..length] )
41
+
42
+ # And reconstruct the stream contents to the first 8 bytes (header)
43
+ # Plus our decompressed body
44
+ contents = contents[0..7] + body
45
+ end
46
+
47
+ # Determine the nbits of our dimensions rectangle
48
+ nbits = contents.unpack('C' * contents.length)[8] >> 3
49
+
50
+ # Determine how many bits long this entire RECT structure is
51
+ rectbits = 5 + nbits * 4 # 5 bits for nbits, as well as nbits * number of fields (4)
52
+
53
+ # Determine how many bytes rectbits composes (ceil(rectbits/8))
54
+ rectbytes = (rectbits.to_f / 8).ceil
55
+
56
+ # Unpack the RECT structure from the stream in little-endian bit order, then join it into a string
57
+ rect = contents[8..(8 + rectbytes)].unpack("#{'B8' * rectbytes}").join()
58
+
59
+ # Read in nbits incremenets starting from 5
60
+ dimensions = Array.new
61
+ 4.times do |n|
62
+ s = 5 + (n * nbits) # Calculate our start index
63
+ e = s + (nbits - 1) # Calculate our end index
64
+ dimensions[n] = rect[s..e].to_i(2) # Read that range (binary) and convert it to an integer
65
+ end
66
+
67
+ # The values we have here are in "twips"
68
+ # 20 twips to a pixel (that's why SWFs are fuzzy sometimes!)
69
+ width = (dimensions[1] - dimensions[0]) / 20
70
+ height = (dimensions[3] - dimensions[2]) / 20
71
+
72
+ # If you can't figure this one out, you probably shouldn't have read this far
73
+ # jplopez : Adds swf version
74
+ return [width, height, version]
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
data/lib/parser.rb ADDED
@@ -0,0 +1,20 @@
1
+ Dir[File.join(File.dirname(__FILE__), 'parser/*.rb')].each { |parser| require parser }
2
+
3
+ class ImageSpec
4
+
5
+ module Parser
6
+
7
+ def self.formats
8
+ @@formats ||= constants.collect { |format| const_get(format) }
9
+ end
10
+
11
+ def self.parse(stream)
12
+ formats.each do |format|
13
+ return format.attributes(stream) if format.detected?(stream)
14
+ end
15
+ raise "#{stream.inspect} is not a supported image format. Sorry bub :("
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :image_spec do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+
3
+ require 'image_spec'
4
+
5
+ class ImageSpecTest < Test::Unit::TestCase
6
+ # Replace this with your real tests.
7
+
8
+ def setup
9
+ @swf_file_path = "/home/jplopez/development/adxion_300x250.swf"
10
+ end
11
+
12
+ def test_swf_parser_version_attribute
13
+ instance = ImageSpec.new(@swf_file_path)
14
+ assert_not_nil instance
15
+ assert_not_nil instance.version
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-imagespec-jp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brandon Anderson
9
+ - Michael Sheakoski
10
+ - Mike Boone
11
+ - Dimitrij Denissenko
12
+ - Juan Pablo Lopez
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+ date: 2013-02-04 00:00:00.000000000 Z
17
+ dependencies: []
18
+ description: A lightweight module designed to extract the width/height dimensions
19
+ of various image types. Also supports SWFs. No supports SWF version too.
20
+ email: anderson.brandon@gmail.com
21
+ executables: []
22
+ extensions: []
23
+ extra_rdoc_files:
24
+ - LICENSE
25
+ - README
26
+ files:
27
+ - LICENSE
28
+ - README
29
+ - Rakefile
30
+ - VERSION
31
+ - init.rb
32
+ - lib/image_spec.rb
33
+ - lib/parser.rb
34
+ - lib/parser/gif.rb
35
+ - lib/parser/jpeg.rb
36
+ - lib/parser/png.rb
37
+ - lib/parser/swf.rb
38
+ - tasks/image_spec_tasks.rake
39
+ - test/image_spec_test.rb
40
+ homepage: http://github.com/jplopez/ruby-imagespec
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.21
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Image/Flash width/height dimensions extractor
65
+ test_files:
66
+ - test/image_spec_test.rb