gif-info 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ gem "struct-fx", ">= 0.1.1"
5
+ gem "abstract", ">= 1.0.0"
6
+ gem "frozen-objects", ">= 0.2.0"
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.5.2"
13
+ gem "riot", ">= 0.12.1"
14
+ end
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ bit-packer (0.1.0)
6
+ lookup-hash (>= 0.2.0)
7
+ frozen-objects (0.2.0)
8
+ git (1.2.5)
9
+ hash-utils (0.11.0)
10
+ jeweler (1.5.2)
11
+ bundler (~> 1.0.0)
12
+ git (>= 1.2.5)
13
+ rake
14
+ lookup-hash (0.2.0)
15
+ hash-utils (>= 0.11.0)
16
+ rake (0.8.7)
17
+ riot (0.12.2)
18
+ rr
19
+ rr (1.0.2)
20
+ struct-fx (0.1.1)
21
+ bit-packer (>= 0.1.0)
22
+ frozen-objects (>= 0.2.0)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ abstract (>= 1.0.0)
29
+ bundler (~> 1.0.0)
30
+ frozen-objects (>= 0.2.0)
31
+ jeweler (~> 1.5.2)
32
+ riot (>= 0.12.1)
33
+ struct-fx (>= 0.1.1)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Martin Kozák
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,52 @@
1
+ Gif Info
2
+ ========
3
+
4
+ **gif-info** is analyzer of the [GIF image format][1]. It performs complete
5
+ analysis of internal GIF block structure and streams it as an "object
6
+ stream" with metainformations of each block. Also can *interpret* internal
7
+ structure by providing the simple object-like interface to base image
8
+ file informations. Works above all seekable IO streams, so allows
9
+ processing of the big files too. Doesn't perform [LZW][2] decompressing,
10
+ returns raw data for both color tables and images.
11
+
12
+ Two different approaches are available: **sequential** and **static**.
13
+ First one yields "stream" of objects which are equivalent to functional
14
+ blocks in the GIF file and which contain low-level GIF data. It's
15
+ equivalent of for example [SAX][3] parser although, of sure, less
16
+ complex. The other one provides classical single object-like access to
17
+ interpreted file informations.
18
+
19
+ Examples of both are available in the `bin` directory. `git-info`
20
+ command writes out content of the static information object, `git-dump`
21
+ dumps content of low level blocks stream.
22
+
23
+ Modifiing the file and writing changes back is possible (see [StructFx][5]
24
+ library documentation). It isn't implemented directly by this library,
25
+ but should be easy to implement it if you will need it -- with exception
26
+ of data blocks as comments or image data -- it's necessary split them
27
+ to blocks manually in your writing routine. Other structures provided
28
+ by the library contains binary serialization routines implicitly.
29
+
30
+ Contributing
31
+ ------------
32
+
33
+ 1. Fork it.
34
+ 2. Create a branch (`git checkout -b 20101220-my-change`).
35
+ 3. Commit your changes (`git commit -am "Added something"`).
36
+ 4. Push to the branch (`git push origin 20101220-my-change`).
37
+ 5. Create an [Issue][6] with a link to your branch.
38
+ 6. Enjoy a refreshing Diet Coke and wait.
39
+
40
+ Copyright
41
+ ---------
42
+
43
+ Copyright © 2011 [Martin Kozák][7]. See `LICENSE.txt` for
44
+ further details.
45
+
46
+ [1]: http://www.matthewflickinger.com/lab/whatsinagif/
47
+ [2]: http://en.wikipedia.org/wiki/LZW
48
+ [3]: http://en.wikipedia.org/wiki/Simple_API_for_XML
49
+ [4]: http://en.wikipedia.org/wiki/Document_Object_Model
50
+ [5]: https://github.com/martinkozak/struct-fx
51
+ [6]: http://github.com/martinkozak/gif-info/issues
52
+ [7]: http://www.martinkozak.net/
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "gif-info"
17
+ gem.homepage = "http://github.com/martinkozak/gif-info"
18
+ gem.license = "MIT"
19
+ gem.summary = 'Pure Ruby analyzer of the GIF image format. Performs complete analysis of internal GIF block structure and streams it as an objects stream with metainformations of each block. Also can interpret internal structure by providing the simple object-like interface to base image file informations. Works above seekable IO streams, so allows processing of the big files too. Doesn\'t perform LZW decompressing, returns raw data for both color tables and images.'
20
+ gem.email = "martinkozak@martinkozak.net"
21
+ gem.authors = ["Martin Kozák"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/rdoctask'
30
+ Rake::RDocTask.new do |rdoc|
31
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
32
+
33
+ rdoc.rdoc_dir = 'rdoc'
34
+ rdoc.title = "hash-utils #{version}"
35
+ rdoc.rdoc_files.include('README*')
36
+ rdoc.rdoc_files.include('lib/**/*.rb')
37
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
Binary file
Binary file
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # (c) 2011 Martin Kozák (martinkozak@martinkozak.net)f
4
+
5
+ if ARGV[0].nil? or (ARGV[0] == "--help")
6
+ puts "Usage: gif-dump [--help|--version|FILE]"
7
+ puts "\t--help display this help and exit"
8
+ puts "\t--version output version information and exit"
9
+
10
+ exit
11
+ elsif ARGV[0] == "--version"
12
+ puts "gif-info 0.1.0"
13
+ puts "Copyright (C) 2011 Martin Kozák (martinkozak@martinkozak.net)"
14
+ puts "Dumps all structure informations from given GIF file."
15
+ exit
16
+ end
17
+
18
+ ###
19
+
20
+ require "gif-info"
21
+
22
+ def __render(struct, level)
23
+ struct.members.each do |item|
24
+ if item == :packed
25
+ puts (" " * level) << "packed"
26
+ __render(struct[item].data, level + 1)
27
+ else
28
+ puts (" " * level) << item.to_s << " " << struct[item].to_s
29
+ end
30
+ end
31
+ end
32
+
33
+ # Analyzes
34
+ File::open(ARGV[0], "rb") do |io|
35
+ GifInfo::parse(io) do |block|
36
+ if block.kind_of? GifInfo::FixedBlock
37
+ puts "\n" << block.class.name
38
+ __render(block.header.data, 1)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ # (c) 2011 Martin Kozák (martinkozak@martinkozak.net)f
4
+
5
+ if ARGV[0].nil? or (ARGV[0] == "--help")
6
+ puts "Usage: gif-info [--help|--version|FILE]"
7
+ puts "\t--help display this help and exit"
8
+ puts "\t--version output version information and exit"
9
+
10
+ exit
11
+ elsif ARGV[0] == "--version"
12
+ puts "gif-info 0.1.0"
13
+ puts "Copyright (C) 2011 Martin Kozák (martinkozak@martinkozak.net)"
14
+ puts "Writes out informations about given GIF file."
15
+ exit
16
+ end
17
+
18
+ ###
19
+
20
+ require "gif-info"
21
+
22
+ # Analyzes
23
+ f = GifInfo::analyze_file(ARGV[0])
24
+
25
+ # Writes out
26
+ puts "type " << f.type.to_s
27
+ puts "version " << f.version.to_s
28
+ puts "images_count " << f.images_count.to_s
29
+ puts "width " << f.width.to_s
30
+ puts "height " << f.height.to_s
31
+ puts "color_resolution " << f.color_resolution.to_s
32
+
33
+ if not f.pixel_aspect_ratio.nil?
34
+ puts "pixel_aspect_ratio " << f.pixel_aspect_ratio.to_s
35
+ end
36
+
37
+ puts "transparent " << f.transparent?.to_s
38
+ puts "interlaced " << f.interlaced?.to_s
39
+ puts "animated " << f.animated?.to_s
40
+ puts "cyclic " << f.cyclic?.to_s
41
+
42
+ if f.comments.length > 0
43
+ puts "comment " << f.comments.first
44
+ end
@@ -0,0 +1,86 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gif-info}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Martin Kozák"]
12
+ s.date = %q{2011-03-10}
13
+ s.email = %q{martinkozak@martinkozak.net}
14
+ s.executables = ["gif-dump", "gif-info"]
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "ajax-loader-0.gif",
28
+ "ajax-loader.gif",
29
+ "bin/gif-dump",
30
+ "bin/gif-info",
31
+ "gif-info.gemspec",
32
+ "lib/gif-info.rb",
33
+ "lib/gif-info/block.rb",
34
+ "lib/gif-info/blocks/application-extension.rb",
35
+ "lib/gif-info/blocks/comment-extension.rb",
36
+ "lib/gif-info/blocks/global-color-table.rb",
37
+ "lib/gif-info/blocks/graphics-control-extension.rb",
38
+ "lib/gif-info/blocks/header-block.rb",
39
+ "lib/gif-info/blocks/image-data.rb",
40
+ "lib/gif-info/blocks/image-descriptor.rb",
41
+ "lib/gif-info/blocks/local-color-table.rb",
42
+ "lib/gif-info/blocks/logical-screen-descriptor.rb",
43
+ "lib/gif-info/blocks/plain-text-extension.rb",
44
+ "lib/gif-info/blocks/trailer.rb",
45
+ "lib/gif-info/body.rb",
46
+ "lib/gif-info/color-table.rb",
47
+ "lib/gif-info/data-block.rb",
48
+ "lib/gif-info/dynamic-block.rb",
49
+ "lib/gif-info/fixed-block.rb",
50
+ "lib/gif-info/raw-block.rb",
51
+ "test"
52
+ ]
53
+ s.homepage = %q{http://github.com/martinkozak/gif-info}
54
+ s.licenses = ["MIT"]
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.6.2}
57
+ s.summary = %q{Pure Ruby analyzer of the GIF image format. Performs complete analysis of internal GIF block structure and streams it as an objects stream with metainformations of each block. Also can interpret internal structure by providing the simple object-like interface to base image file informations. Works above seekable IO streams, so allows processing of the big files too. Doesn't perform LZW decompressing, returns raw data for both color tables and images.}
58
+
59
+ if s.respond_to? :specification_version then
60
+ s.specification_version = 3
61
+
62
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
63
+ s.add_runtime_dependency(%q<struct-fx>, [">= 0.1.1"])
64
+ s.add_runtime_dependency(%q<abstract>, [">= 1.0.0"])
65
+ s.add_runtime_dependency(%q<frozen-objects>, [">= 0.2.0"])
66
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
67
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
68
+ s.add_development_dependency(%q<riot>, [">= 0.12.1"])
69
+ else
70
+ s.add_dependency(%q<struct-fx>, [">= 0.1.1"])
71
+ s.add_dependency(%q<abstract>, [">= 1.0.0"])
72
+ s.add_dependency(%q<frozen-objects>, [">= 0.2.0"])
73
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
74
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
75
+ s.add_dependency(%q<riot>, [">= 0.12.1"])
76
+ end
77
+ else
78
+ s.add_dependency(%q<struct-fx>, [">= 0.1.1"])
79
+ s.add_dependency(%q<abstract>, [">= 1.0.0"])
80
+ s.add_dependency(%q<frozen-objects>, [">= 0.2.0"])
81
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
82
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
83
+ s.add_dependency(%q<riot>, [">= 0.12.1"])
84
+ end
85
+ end
86
+
@@ -0,0 +1,407 @@
1
+ # encoding: utf-8
2
+ # (c) 2011 Martin Kozák (martinkozak@martinkozak.net)
3
+
4
+ require "stringio"
5
+ require "struct-fx"
6
+
7
+ require "gif-info/blocks/header-block"
8
+ require "gif-info/blocks/logical-screen-descriptor"
9
+ require "gif-info/blocks/global-color-table"
10
+ require "gif-info/blocks/local-color-table"
11
+ require "gif-info/blocks/plain-text-extension"
12
+ require "gif-info/blocks/comment-extension"
13
+ require "gif-info/blocks/application-extension"
14
+ require "gif-info/blocks/graphics-control-extension"
15
+ require "gif-info/blocks/image-descriptor"
16
+ require "gif-info/blocks/image-data"
17
+ require "gif-info/blocks/trailer"
18
+
19
+ ##
20
+ # Primary GifInfo module.
21
+ #
22
+
23
+ class GifInfo
24
+
25
+ ############################################################
26
+ ## STATIC PART
27
+ ############################################################
28
+
29
+ ##
30
+ # Defines structure of the block head.
31
+ #
32
+
33
+ BLOCK_HEAD = StructFx::new do
34
+ uint8 :block_introducer
35
+ uint8 :extension_label
36
+ end
37
+
38
+ ##
39
+ # Parses the GIF file.
40
+ #
41
+ # @param [IO] io IO object where offset 0 is start of the GIF file
42
+ # @yield [Blocks::ApplicationExtension]
43
+ # @yield [Blocks::CommentExtension]
44
+ # @yield [Blocks::GlobalColorTable]
45
+ # @yield [Blocks::GraphicsControlExtension]
46
+ # @yield [Blocks::HeaderBlock]
47
+ # @yield [Blocks::ImageData]
48
+ # @yield [Blocks::ImageDescriptor]
49
+ # @yield [Blocks::LocalColorTable]
50
+ # @yield [Blocks::LogicalScreenDescriptor]
51
+ # @yield [Blocks::PlainTextExtension]
52
+ # @yield [Blocks::Trailer]
53
+ # @see http://www.matthewflickinger.com/lab/whatsinagif/
54
+ #
55
+
56
+ def self.parse(io)
57
+ __parse(io) do |block|
58
+
59
+ # Saves position of beginning of the next block set by
60
+ # inner parser
61
+ position = io.pos
62
+
63
+ # Yields block and allows application seek trough the file
64
+ # according to its needs
65
+ yield block
66
+
67
+ # Seeks to position at beginning of the next block
68
+ io.seek(position)
69
+
70
+ end
71
+ end
72
+
73
+
74
+ private
75
+
76
+ ##
77
+ # Just performs parsing of the GIF file.
78
+ #
79
+
80
+ def self.__parse(io)
81
+ if io.kind_of? String
82
+ io = StringIO::new(io)
83
+ end
84
+
85
+ # Header Block
86
+ yield Blocks::HeaderBlock::new(io)
87
+
88
+ # Logical Screen Descriptor
89
+ yield lsd = Blocks::LogicalScreenDescriptor::new(io)
90
+
91
+ # Global Color Table
92
+ packed = lsd.header.data.packed.data
93
+ if packed.global_color_table
94
+ size = packed.global_color_table_size
95
+ yield Blocks::GlobalColorTable::new(io, size)
96
+ end
97
+
98
+ # Extensions
99
+ reader = self::BLOCK_HEAD
100
+ length = reader.length
101
+
102
+ loop do
103
+ reader << (io.read(length) << "\0") # adds zero character for cases, trailer is last byte of the file
104
+ header = self::BLOCK_HEAD.data
105
+ io.seek(-length, IO::SEEK_CUR)
106
+
107
+ case header.block_introducer
108
+ when 0x21 # extension
109
+ case header.extension_label
110
+ when 0xF9 # graphics control
111
+ yield Blocks::GraphicsControlExtension::new(io)
112
+ when 0xFF # application
113
+ yield Blocks::ApplicationExtension::new(io)
114
+ when 0xFE # comment
115
+ yield Blocks::CommentExtension::new(io)
116
+ when 0x01 # plain text
117
+ yield Blocks::PlainTextExtension::new(io)
118
+ else
119
+ raise Exception::new("Invalid format: 0x01, 0xF9, 0xFE or 0xFF expected, but 0x" << header.block_introducer.to_s(16).upcase << " found at position " << (io.pos + 1).to_s << ".")
120
+ end
121
+
122
+ when 0x2C # image descriptor
123
+
124
+ # Image Descriptor
125
+ yield desc = Blocks::ImageDescriptor::new(io)
126
+
127
+ # Local Color Table
128
+ if desc.header.data.packed.data.local_color_table
129
+ size = lsd.header.data.packed.data.local_color_table_size
130
+ yield Blocks::LocalColorTable::new(io, size)
131
+ end
132
+
133
+ # Image Data
134
+ yield Blocks::ImageData::new(io)
135
+
136
+ when 0x3B # trailer
137
+ yield Blocks::Trailer::new(io)
138
+ break
139
+
140
+ else
141
+ raise Exception::new("Invalid format: 0x21, 0x2C or 0x3B expected, but 0x" << header.block_introducer.to_s(16).upcase << " found at position " << io.pos.to_s << ".")
142
+ end
143
+ end
144
+ end
145
+
146
+
147
+ public
148
+
149
+ ##
150
+ # Considers stream, performs analyzing and returns info object
151
+ # as result.
152
+ #
153
+ # @param [IO] io IO object with GIF data
154
+ # @return [GifInfo] info object
155
+ #
156
+
157
+ def self.analyze_io(io)
158
+ self::new(io)
159
+ end
160
+
161
+ ##
162
+ # Analyzes string with GIF data and returns info object.
163
+ #
164
+
165
+ def self.analyze_string(string)
166
+ self::analyze_io(StringIO::new(string))
167
+ end
168
+
169
+ ##
170
+ # Analyzes file and returns info object back.
171
+ #
172
+ # @param [String] filename file path
173
+ # @return [GifInfo] info object
174
+ #
175
+
176
+ def self.analyze_file(filename)
177
+ File::open(filename, "rb") do |io|
178
+ self.analyze_io(io)
179
+ end
180
+ end
181
+
182
+
183
+ ############################################################
184
+ ## INSTANCE PART
185
+ ############################################################
186
+
187
+ ##
188
+ # Type of the file. If it isn't +:GIF+, it means, file isn't
189
+ # valid GIF gile.
190
+ #
191
+ # @return [Symbol] always +:GIF+
192
+ #
193
+
194
+ attr_reader :type
195
+ @type
196
+
197
+ ##
198
+ # Version of the GIF standard. Can be +:87a+ or +?89a+.
199
+ # @return [Symbol] GIF standard version
200
+ #
201
+
202
+ attr_reader :version
203
+ @version
204
+
205
+ ##
206
+ # Width of the image. (Width of the canvas.)
207
+ # @return [Integer] width
208
+ #
209
+
210
+ attr_reader :width
211
+ @width
212
+
213
+ ##
214
+ # Height of the image. (Height of the canvas.)
215
+ # @return [Integer] height
216
+ #
217
+
218
+ attr_reader :height
219
+ @height
220
+
221
+ ##
222
+ # Pixel aspect ratio. See standard what it is.
223
+ # @return [Integer] pixel aspect ration
224
+ #
225
+
226
+ attr_reader :pixel_aspect_ratio
227
+ @pixel_aspect_ratio
228
+
229
+ ##
230
+ # Color resolution in number of colors which can be encoded
231
+ # according to global table. If local tables found, it's +nil+.
232
+ #
233
+ # @return [Integer] color count
234
+ #
235
+
236
+ attr_reader :color_resolution
237
+ @color_resolution
238
+
239
+ ##
240
+ # Comments inside the file. GIF file can theorethically contain
241
+ # unlimtited number of the comment blocks, so it returns array.
242
+ #
243
+ # @return [Array] array with comments
244
+ #
245
+
246
+ attr_reader :comments
247
+ @comments
248
+
249
+ ##
250
+ # Contains images count. More images in one file are characteristics
251
+ # for the animated GIF files.
252
+ #
253
+ # @return [Integer] images count
254
+ #
255
+
256
+ attr_reader :images_count
257
+ @images_count
258
+
259
+ ##
260
+ # Indicates animation is cyclic.
261
+ #
262
+
263
+ @cyclic
264
+
265
+ ##
266
+ # Indicates, file is animated.
267
+ #
268
+
269
+ @animated
270
+
271
+ ##
272
+ # Indicates, at least one image in file has some color transparent.
273
+ #
274
+
275
+ @transparent
276
+
277
+ ##
278
+ # Indicates, at least one image in file is rendered interlaced.
279
+ #
280
+
281
+ @interlaced
282
+
283
+ ##
284
+ # Constructor.
285
+ # @param [IO] io IO object with GIF data
286
+ #
287
+
288
+ def initialize(io)
289
+ @comments = [ ]
290
+ @images_count = 0
291
+ @cyclic = false
292
+ @animated = false
293
+ @transparent = false
294
+ @interlaced = false
295
+
296
+ self.consider! io
297
+ end
298
+
299
+ ##
300
+ # Considers IO object, analyzes it and sets result ot the object.
301
+ # @param [IO] io IO object with GIF data
302
+ #
303
+
304
+ def consider!(io)
305
+ self.class::parse(io) do |block|
306
+
307
+ # Header Block
308
+ if block.kind_of? GifInfo::Blocks::HeaderBlock
309
+ header = block.header.data
310
+ @type = header.signature.to_sym # type
311
+ @version = header.version.to_sym # version
312
+
313
+ # Logical Screen Descriptor
314
+ elsif block.kind_of? GifInfo::Blocks::LogicalScreenDescriptor
315
+ header = block.header.data
316
+ packed = header.packed.data
317
+
318
+ @width = header.canvas_width # width
319
+ @height = header.canvas_height # height
320
+
321
+ value = header.pixel_aspect_ratio # pixel aspect ratio
322
+ value = nil if value <= 0 #
323
+ @pixel_aspect_ratio = value #
324
+
325
+ if packed.global_color_table # color resolution
326
+ @color_resolution = 2 ** (packed.global_color_table_size + 1)
327
+ end
328
+
329
+ # Comments
330
+ elsif block.kind_of? GifInfo::Blocks::CommentExtension
331
+ @comments << block.body.data # comments
332
+
333
+ # Image Descriptor
334
+ elsif block.kind_of? GifInfo::Blocks::ImageDescriptor
335
+ packed = block.header.data.packed.data
336
+
337
+ @images_count += 1 # images count
338
+ @animated = true if @images_count == 2 # animated
339
+ @interlaced |= packed.interlace # interlaced
340
+
341
+ if packed.local_color_table and (not @color_resolution.nil?) and (packed.local_color_table_size != @color_resolution)
342
+ @color_resolution = nil # resets color resolution if local color table found
343
+ end # and global and local aren't equivalent
344
+
345
+ # Application Extension
346
+ elsif block.kind_of? GifInfo::Blocks::ApplicationExtension
347
+ header = block.header.data
348
+ if (header.application_identifier == "NETSCAPE") and (header.application_authentication_code == "2.0")
349
+ @cyclic = true # cyclic
350
+ end
351
+
352
+ # Graphics Control Extension
353
+ elsif block.kind_of? GifInfo::Blocks::GraphicsControlExtension
354
+ packed = block.header.data.packed.data
355
+ @transparent |= packed.transparent_color # transparent
356
+
357
+ end
358
+
359
+ end
360
+
361
+ ##
362
+ # Indicates animation is cyclic. In strange GIF files can be set
363
+ # although file isn't animated and contains single image only.
364
+ #
365
+ # @return [Boolean] +true+ if yes, +false+ in otherwise
366
+ #
367
+
368
+ def cyclic?
369
+ @cyclic
370
+ end
371
+
372
+ ##
373
+ # Indicates file is animated. It can be set to +true+ although
374
+ # animation isn't run because it's set if file contains
375
+ # more images.
376
+ #
377
+ # @return [Boolean] +true+ if yes, +false+ in otherwise
378
+ #
379
+
380
+ def animated?
381
+ @animated
382
+ end
383
+
384
+ ##
385
+ # Indicates, at least one image in file has some color
386
+ # transparent. It of sure doesn't mean, image is transparent.
387
+ # It only means, transparency is turned on.
388
+ #
389
+ # @return [Boolean] +true+ if yes, +false+ in otherwise
390
+ #
391
+
392
+ def transparent?
393
+ @transparent
394
+ end
395
+
396
+ ##
397
+ # Indicates, at least one image in file is rendered interlaced.
398
+ # @return [Boolean] +true+ if yes, +false+ in otherwise
399
+ #
400
+
401
+ def interlaced?
402
+ @interlaced
403
+ end
404
+
405
+ end
406
+
407
+ end