gif-info 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +33 -0
- data/LICENSE.txt +20 -0
- data/README.md +52 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/ajax-loader-0.gif +0 -0
- data/ajax-loader.gif +0 -0
- data/bin/gif-dump +41 -0
- data/bin/gif-info +44 -0
- data/gif-info.gemspec +86 -0
- data/lib/gif-info.rb +407 -0
- data/lib/gif-info/block.rb +84 -0
- data/lib/gif-info/blocks/application-extension.rb +38 -0
- data/lib/gif-info/blocks/comment-extension.rb +35 -0
- data/lib/gif-info/blocks/global-color-table.rb +25 -0
- data/lib/gif-info/blocks/graphics-control-extension.rb +43 -0
- data/lib/gif-info/blocks/header-block.rb +35 -0
- data/lib/gif-info/blocks/image-data.rb +35 -0
- data/lib/gif-info/blocks/image-descriptor.rb +45 -0
- data/lib/gif-info/blocks/local-color-table.rb +25 -0
- data/lib/gif-info/blocks/logical-screen-descriptor.rb +43 -0
- data/lib/gif-info/blocks/plain-text-extension.rb +77 -0
- data/lib/gif-info/blocks/trailer.rb +32 -0
- data/lib/gif-info/body.rb +105 -0
- data/lib/gif-info/color-table.rb +32 -0
- data/lib/gif-info/data-block.rb +56 -0
- data/lib/gif-info/dynamic-block.rb +66 -0
- data/lib/gif-info/fixed-block.rb +82 -0
- data/lib/gif-info/raw-block.rb +78 -0
- data/test +112 -0
- metadata +157 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "gif-info/block"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Primary GifInfo module.
|
8
|
+
#
|
9
|
+
|
10
|
+
class GifInfo
|
11
|
+
|
12
|
+
##
|
13
|
+
# General blocks module.
|
14
|
+
#
|
15
|
+
|
16
|
+
module Blocks
|
17
|
+
|
18
|
+
##
|
19
|
+
# Indicates the end of the file.
|
20
|
+
#
|
21
|
+
|
22
|
+
class Trailer < Block
|
23
|
+
##
|
24
|
+
# Skips block in stream.
|
25
|
+
#
|
26
|
+
|
27
|
+
def skip!
|
28
|
+
@io.seek(1, IO::SEEK_CUR)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
##
|
5
|
+
# Primary GifInfo module.
|
6
|
+
#
|
7
|
+
|
8
|
+
class GifInfo
|
9
|
+
|
10
|
+
##
|
11
|
+
# Decoder and holder of block-encoded GIF data.
|
12
|
+
#
|
13
|
+
|
14
|
+
class Body
|
15
|
+
|
16
|
+
##
|
17
|
+
# IO object.
|
18
|
+
#
|
19
|
+
|
20
|
+
@io
|
21
|
+
|
22
|
+
##
|
23
|
+
# Position in stream.
|
24
|
+
#
|
25
|
+
|
26
|
+
@position
|
27
|
+
|
28
|
+
##
|
29
|
+
# Data contained in the data body.
|
30
|
+
#
|
31
|
+
|
32
|
+
@data
|
33
|
+
|
34
|
+
##
|
35
|
+
# Constructor.
|
36
|
+
# @param [IO] io IO object
|
37
|
+
#
|
38
|
+
|
39
|
+
def initialize(io)
|
40
|
+
@io = io
|
41
|
+
@position = io.pos
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Returns data.
|
46
|
+
# If block given, streams it, in otherwise returns full value.
|
47
|
+
#
|
48
|
+
# @yield [String] chunk in size of one data block of the raw data
|
49
|
+
# @return [String] full data content
|
50
|
+
#
|
51
|
+
|
52
|
+
def data(&block)
|
53
|
+
if not @data.nil?
|
54
|
+
return @data
|
55
|
+
end
|
56
|
+
|
57
|
+
self.prepare! # seeks to block position
|
58
|
+
|
59
|
+
if not block.nil?
|
60
|
+
loop do
|
61
|
+
size = @io.getbyte
|
62
|
+
break if size <= 0
|
63
|
+
block.call(@io.read(size))
|
64
|
+
end
|
65
|
+
else
|
66
|
+
data = ""
|
67
|
+
self.data do |chunk|
|
68
|
+
data << chunk
|
69
|
+
end
|
70
|
+
@data = data
|
71
|
+
|
72
|
+
return @data
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Skips the body content in stream.
|
78
|
+
#
|
79
|
+
|
80
|
+
def skip!
|
81
|
+
loop do
|
82
|
+
size = @io.getbyte
|
83
|
+
break if size <= 0
|
84
|
+
@io.seek(size, IO::SEEK_CUR)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Prepares for reading.
|
90
|
+
#
|
91
|
+
|
92
|
+
def prepare!
|
93
|
+
@io.seek(@position)
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Returns bytesize of the data body.
|
98
|
+
# @return [Integer] length in bytes
|
99
|
+
#
|
100
|
+
|
101
|
+
def bytesize
|
102
|
+
self.data.bytesize
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "gif-info/raw-block"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Primary GifInfo module.
|
8
|
+
#
|
9
|
+
|
10
|
+
class GifInfo
|
11
|
+
|
12
|
+
##
|
13
|
+
# General color table block.
|
14
|
+
# @abstract
|
15
|
+
#
|
16
|
+
|
17
|
+
class ColorTable < RawBlock
|
18
|
+
|
19
|
+
##
|
20
|
+
# Constructor.
|
21
|
+
#
|
22
|
+
# @param [IO] io IO object
|
23
|
+
# @param [Integer] size size as it's reported by header blocks
|
24
|
+
#
|
25
|
+
|
26
|
+
def initialize(io, size)
|
27
|
+
super(io, 3 * (2 ** (size + 1)))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "gif-info/block"
|
5
|
+
require "gif-info/body"
|
6
|
+
|
7
|
+
##
|
8
|
+
# Primary GifInfo module.
|
9
|
+
#
|
10
|
+
|
11
|
+
class GifInfo
|
12
|
+
|
13
|
+
##
|
14
|
+
# Abstract block which contains data in {Body} form only.
|
15
|
+
# @abstract
|
16
|
+
#
|
17
|
+
|
18
|
+
class DataBlock < Block
|
19
|
+
|
20
|
+
##
|
21
|
+
# Data body content.
|
22
|
+
#
|
23
|
+
|
24
|
+
@body
|
25
|
+
|
26
|
+
##
|
27
|
+
# Returns data body.
|
28
|
+
# @return [Body] data body
|
29
|
+
#
|
30
|
+
|
31
|
+
def body
|
32
|
+
if @body.nil?
|
33
|
+
@body = Body::new(@io)
|
34
|
+
end
|
35
|
+
|
36
|
+
return @body
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Skips block in stream.
|
41
|
+
#
|
42
|
+
|
43
|
+
def skip!
|
44
|
+
self.body.skip!
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Returns block size.
|
49
|
+
# @return [Integer] block size in bytes
|
50
|
+
#
|
51
|
+
|
52
|
+
def bytesize
|
53
|
+
self.body.bytesize
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "gif-info/fixed-block"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Primary GifInfo module.
|
8
|
+
#
|
9
|
+
|
10
|
+
class GifInfo
|
11
|
+
|
12
|
+
##
|
13
|
+
# Abstract block which contains both header and data with dynamic
|
14
|
+
# (non-fixed) length.
|
15
|
+
#
|
16
|
+
# @abstract
|
17
|
+
#
|
18
|
+
|
19
|
+
class DynamicBlock < FixedBlock
|
20
|
+
|
21
|
+
##
|
22
|
+
# Holds data body.
|
23
|
+
#
|
24
|
+
|
25
|
+
@body
|
26
|
+
|
27
|
+
##
|
28
|
+
# Returns data body.
|
29
|
+
#
|
30
|
+
# @param [Integer] skip number of bytes to skip before data
|
31
|
+
# @return [Body] data body
|
32
|
+
#
|
33
|
+
|
34
|
+
def body(skip = nil)
|
35
|
+
if @body.nil?
|
36
|
+
if not skip.nil?
|
37
|
+
@io.seek(skip, IO::SEEK_CUR) # skips dummy leader
|
38
|
+
end
|
39
|
+
@body = Body::new(@io)
|
40
|
+
end
|
41
|
+
|
42
|
+
@body
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Skips block in stream.
|
47
|
+
#
|
48
|
+
|
49
|
+
def skip!(additional = nil)
|
50
|
+
super()
|
51
|
+
if not additional.nil?
|
52
|
+
@io.seek(additional, IO::SEEK_CUR)
|
53
|
+
end
|
54
|
+
self.body.skip!
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Returns block size.
|
59
|
+
# @return [Integer] block size in bytes
|
60
|
+
#
|
61
|
+
|
62
|
+
def bytesize
|
63
|
+
self.header.bytesize + self.body.bytesize
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "struct-fx" # 0.1.1
|
5
|
+
require "gif-info/block"
|
6
|
+
|
7
|
+
##
|
8
|
+
# Primary GifInfo module.
|
9
|
+
#
|
10
|
+
|
11
|
+
class GifInfo
|
12
|
+
|
13
|
+
##
|
14
|
+
# Abstract fixed-size block which contains header only.
|
15
|
+
# @abstract
|
16
|
+
#
|
17
|
+
|
18
|
+
class FixedBlock < Block
|
19
|
+
|
20
|
+
##
|
21
|
+
# Holds header.
|
22
|
+
#
|
23
|
+
|
24
|
+
@header
|
25
|
+
|
26
|
+
##
|
27
|
+
# Holds header struct.
|
28
|
+
#
|
29
|
+
# In case, data are loaded, @header and @struct links to the
|
30
|
+
# same objects.
|
31
|
+
#
|
32
|
+
|
33
|
+
@struct
|
34
|
+
|
35
|
+
##
|
36
|
+
# Returns header struct.
|
37
|
+
# @return [StructFx] struct
|
38
|
+
#
|
39
|
+
|
40
|
+
def header
|
41
|
+
if @header.nil?
|
42
|
+
self.prepare!
|
43
|
+
@header = __struct
|
44
|
+
@header << @io.read(@header.bytesize)
|
45
|
+
end
|
46
|
+
|
47
|
+
@header
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Skips block in stream.
|
52
|
+
#
|
53
|
+
|
54
|
+
def skip!
|
55
|
+
@io.seek(__struct.bytesize, IO::SEEK_CUR)
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Returns block size.
|
60
|
+
# @return [Integer] block size in bytes
|
61
|
+
#
|
62
|
+
|
63
|
+
def bytesize
|
64
|
+
self.header.bytesize
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
##
|
71
|
+
# Returns header struct.
|
72
|
+
#
|
73
|
+
|
74
|
+
def __struct
|
75
|
+
if @struct.nil?
|
76
|
+
@struct = StructFx::new(&self.class::STRUCTURE)
|
77
|
+
end
|
78
|
+
|
79
|
+
@struct
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
|
3
|
+
|
4
|
+
require "gif-info/block"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Primary GifInfo module.
|
8
|
+
#
|
9
|
+
|
10
|
+
class GifInfo
|
11
|
+
|
12
|
+
##
|
13
|
+
# Abstract block which contains only datas in non-formatted form,
|
14
|
+
# so data which aren't encoded in block form as usuall in GIF.
|
15
|
+
# Typicall example are color tables which site is known in forward.
|
16
|
+
#
|
17
|
+
# @abstract
|
18
|
+
#
|
19
|
+
|
20
|
+
class RawBlock < Block
|
21
|
+
|
22
|
+
##
|
23
|
+
# Data body of block.
|
24
|
+
#
|
25
|
+
|
26
|
+
@body
|
27
|
+
|
28
|
+
##
|
29
|
+
# Indicates length of the data for read.
|
30
|
+
#
|
31
|
+
|
32
|
+
@size
|
33
|
+
|
34
|
+
##
|
35
|
+
# Constructor.
|
36
|
+
#
|
37
|
+
# @param [IO] io IO object
|
38
|
+
# @param [Integer] size amount of data for read
|
39
|
+
#
|
40
|
+
|
41
|
+
def initialize(io, size)
|
42
|
+
@size = size
|
43
|
+
super(io)
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns data body.
|
48
|
+
# @return [String] raw data
|
49
|
+
#
|
50
|
+
|
51
|
+
def body
|
52
|
+
if @body.nil?
|
53
|
+
self.prepare!
|
54
|
+
@body = @io.read(@size)
|
55
|
+
end
|
56
|
+
|
57
|
+
return @body
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Skips block in stream.
|
62
|
+
#
|
63
|
+
|
64
|
+
def skip!
|
65
|
+
@io.seek(@size, IO::SEEK_CUR)
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Returns block size.
|
70
|
+
# @return [Integer] block size in bytes
|
71
|
+
#
|
72
|
+
|
73
|
+
def bytesize
|
74
|
+
self.body.bytesize
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|