simple_gif 0.0.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.
- checksums.yaml +7 -0
- data/lib/simple_gif/size.rb +107 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b9f4059ff0fefe827c694a8eb16268e3c64b20f1
|
4
|
+
data.tar.gz: 3706bd0d9fafb8fe1e332090821b25249ddf5b80
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7566aade650d0d6b04d71cdad549fa7b34af5f179702ae2d3a0b8e6dda2f4f7db621acbec0f168edea77bede7ae76a8dd842bbfe540bb746ffd855d9a01979f4
|
7
|
+
data.tar.gz: 75f3a78957bbf7112d67c7ffe2e4c068eee5e6dbfdc2b401741925d8277e3ace3ad7b45cf016febe148629865c766436ece78d2f73bc49d65a16865e309ad09b
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# TODO
|
2
|
+
# do not store first frame -- use background color
|
3
|
+
# this would help with add[diff:...] for the first frame
|
4
|
+
|
5
|
+
def writeGIF **_kwargs
|
6
|
+
kwargs = {filename: "temp.gif", background: [255,255,255]}.merge _kwargs
|
7
|
+
file = File.open kwargs[:filename], "wb:ASCII-8BIT"
|
8
|
+
|
9
|
+
current = history = width = height = nil
|
10
|
+
yield lambda{ |frame|
|
11
|
+
width, height = frame.is_a?(Array) ? [frame.first.size, frame.size] : [kwargs[:width], kwargs[:height]]
|
12
|
+
history, current = [], Array.new(width * height, kwargs[:background]) unless history
|
13
|
+
step = {}
|
14
|
+
if frame.is_a? Array
|
15
|
+
current = frame.flatten(1).zip(current).map.with_index{ |(color, cur), i|
|
16
|
+
step[i] = color if cur != color
|
17
|
+
color
|
18
|
+
}
|
19
|
+
else
|
20
|
+
for (i, j), color in frame
|
21
|
+
k = i * width + j
|
22
|
+
step[k] = current[k] = color if current[k] != color
|
23
|
+
end
|
24
|
+
end
|
25
|
+
history << step unless step.empty?
|
26
|
+
# p history.size
|
27
|
+
}
|
28
|
+
ensure
|
29
|
+
file.write "GIF89a"
|
30
|
+
|
31
|
+
# Logical Screen Descriptor
|
32
|
+
file.write [width, height].pack "SS"
|
33
|
+
file.write "\xF7\x00\x00"
|
34
|
+
|
35
|
+
# Global Color Table
|
36
|
+
color_table = history.flat_map(&:values).uniq
|
37
|
+
raise "sorry, can't have more than 255 colors" if color_table.size > 255
|
38
|
+
color_table[255] = [([*0..255].reverse - color_table.map(&:first))[0]] * 3
|
39
|
+
color_table.each{ |i| file.write (i || [255,255,255]).pack "CCC" }
|
40
|
+
|
41
|
+
# Comment Extension block
|
42
|
+
file.write "\x21\xFE\x1F"
|
43
|
+
file.write "SimpleGIF (c) Nakilon@gmail.com"
|
44
|
+
file.write "\x00"
|
45
|
+
|
46
|
+
# Application Extension block
|
47
|
+
file.write "\x21\xFF\x0B"
|
48
|
+
file.write "NETSCAPE2.0"
|
49
|
+
file.write "\x03\x01\x00\x00\x00"
|
50
|
+
|
51
|
+
for step in history#.drop 1
|
52
|
+
|
53
|
+
### Graphic Control Extension
|
54
|
+
file.write "\x21\xF9\x04\x01"
|
55
|
+
file.write [100/(kwargs[:fps] || 2)].pack "S"
|
56
|
+
file.write "\xFF\x00"
|
57
|
+
|
58
|
+
left, right = step.map{ |k,| k % width }.minmax
|
59
|
+
top, bottom = step.map{ |k,| k / width }.minmax
|
60
|
+
|
61
|
+
# Image Descriptor
|
62
|
+
file.write "\x2C"
|
63
|
+
file.write [left, top, right-left+1, bottom-top+1].pack "S*"
|
64
|
+
file.write "\x00"
|
65
|
+
|
66
|
+
# Image Data
|
67
|
+
file.write "\x08"
|
68
|
+
|
69
|
+
indices = Array.new((right-left+1) * (bottom-top+1), 255)
|
70
|
+
step.each{ |k,v| indices[
|
71
|
+
k - width*top - left - \
|
72
|
+
(left + width - right - 1)*(k/width - top)
|
73
|
+
] = color_table.index v }
|
74
|
+
|
75
|
+
result = []
|
76
|
+
table = (0..257).zip
|
77
|
+
tree = (0..257).map{[]}
|
78
|
+
s = []
|
79
|
+
indices.zip do |b| sb = s + b
|
80
|
+
next s = sb if sb.inject(tree){ |t,i| t && t[i] }
|
81
|
+
result << [table.index(s), (table.size - 1).to_s(2).size]
|
82
|
+
table << sb
|
83
|
+
sb.inject(tree){ |i,j| i[j] ||= [] }
|
84
|
+
s = b
|
85
|
+
end
|
86
|
+
x = [[256, 9], *result, table.index(s), 257].
|
87
|
+
map{ |i, bs| "%0#{bs || result.last.last}b" % i }.
|
88
|
+
reverse.join.reverse.
|
89
|
+
scan(/.{1,8}/).map{ |i| i.reverse.to_i 2 }
|
90
|
+
|
91
|
+
begin
|
92
|
+
chunk = x[0,255]
|
93
|
+
file.write [chunk.size, *chunk].pack "C*"
|
94
|
+
end while x = x[255..-1]
|
95
|
+
|
96
|
+
file.write "\x00"
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
file.write "\x3B"
|
101
|
+
file.close
|
102
|
+
|
103
|
+
`open -a "/Applications/Google Chrome.app" '#{kwargs[:filename]}'` \
|
104
|
+
if kwargs[:open]
|
105
|
+
end
|
106
|
+
|
107
|
+
require_relative(ARGV[0] || "../../examples/life.rb") if $0 == __FILE__
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_gif
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Maslov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: This is uploaded only for personal usage yet.
|
14
|
+
email: nakilon@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/simple_gif/size.rb
|
20
|
+
homepage: http://rubygems.org/gems/simple_gif
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.0
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.0.14
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: A simple GIF renderer.
|
44
|
+
test_files: []
|