/
GIF.rb
136 lines (133 loc) · 4.77 KB
/
GIF.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# unfinished
def load_gif(filename)
GIF.new(filename)
end
class GIF
attr_accessor :version, :gtable, :width, :height, :bgcolor
Color ||= Struct.new(:red, :green, :blue)
ImageDescriptor = 0x2C
Extension = 0x21
CommentExtension = 0xFE
GraphicControlExtension = 0xF9
PlainTextExtension = 0x01
ApplicationExtension = 0xFF
Trailer = 0x3B
def initialize(filename)
data = open(filename, "rb")
#### Header
raise TypeError, "Not a valid gif!" if data.read(3) != "GIF"
@version = data.read(3) #=> 87a|89a
#### GIF Data Stream
reada = ->(bytes = 1){ data.read(bytes) }
readc = ->{ data.read(1).unpack("C")[0] }
reads = ->{ data.read(2).unpack("S")[0] }
### Logical Screen Descriptor
@width = reads.call#
@height = reads.call#
packed_fields = readc.call
@bgcolor = readc.call#
pixel_aspect_ratio = readc.call #
## Unpack packed fields
gtable_flag = packed_fields & 0x80
color_resoluTion = packed_fields & 0x70#
sort_flag = packed_fields & 0x08#
pixel = packed_fields & 0x07
### Global Color Table
@gtable = reada.(3 * 2 ** (pixel + 1)).split("").each_slice(3).collect{|c|
Color.new(*c.map{|x| x.unpack("C")[0]})} if gtable_flag == 0x80
#
while (descriptor = readc.call) != Trailer
case descriptor
when ImageDescriptor
x = reads.call
y = reads.call
width = reads.call
height = reads.call
packed_fields = readc.call
# Unpack packed fields
raise Exception, "Unexpected Error!" if packed_fields & 0x18 != 0x00
ltable_flag = packed_fields & 0x80
interlace_flag = packed_fields & 0x40
sort_flag = packed_fields & 0x20#
pixel = packed_fields & 0x07
## Local Color Table
table = nil
table = reada.(3 * 2 ** (pixel + 1)).split("").each_slice(3).collect{|c|
Color.new(*c.map{|x| x.unpack("C")[0]})} if ltable_flag == 0x80
## Table-Based Image Data
# LZW Minimum Code Size => Clear Code
clear_code = 1 << readc.call#
# Image Data
while (code_size = readc.call) != 0x00
# Data Sub-blocks
code = reada.(code_size)
#================#
# Decode #
#================#
#dictionary =
if interlace_flag == 0x40 # Interlace
else # Continuous
end
#================#
# Draw #
#================#
end
# reset
disposal_method = 0
use_input_flag = 0
transparent_color_flag = 0
delay_time = 1
transparent_color_index = 0
when Extension
case readc.call
when CommentExtension
code = reada.(code_size) while (code_size = readc.call) != 0x00
when GraphicControlExtension
raise Exception, "Unexpected Error!" if readc.call != 0x04
packed_fields = readc.call
delay_time = reads.call#
transparent_color_index = readc.call#
# Unpack packed fields
disposal_method = packed_fields & 0x3C#
use_input_flag = packed_fields & 0x02#
transparent_color_flag = packed_fields & 0x01#
raise Exception, "Unexpected Error!" if readc.call != 0x00
when PlainTextExtension
raise Exception, "Unexpected Error!" if readc.call != 0x0C
text_glid_left_posotion = reads.call#
text_glid_top_posotion = reads.call#
text_glid_width = reads.call#
text_glid_height = reads.call#
character_cell_width = readc.call#
character_cell_height = readc.call#
text_foreground_color_index = readc.call#
text_blackground_color_index = readc.call#
while (code_size = readc.call) != 0x00
# Data Sub-blocks
code = reada.(code_size)
end
#================#
# Draw #
#================#
# reset
disposal_method = 0
use_input_flag = 0
transparent_color_flag = 0
delay_time = 1
transparent_color_index = 0
when ApplicationExtension
raise Exception, "Unexpected Error!" if readc.call != 0x0B
reada.(8)
reada.(3)
code = reada.(code_size) while (code_size = readc.call) != 0x00
end
else
raise Exception, "Unexpected Error!" unless data.pos = data.size - 1
end
end
rescue => e
p e
ensure
data.close
end
end