gif-info 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/.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
|
+
|