spittle 0.9.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/.gitignore +12 -0
- data/README +19 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/bin/spittle +15 -0
- data/examples/sprites/README +5 -0
- data/examples/sprites/apple/apple.png +0 -0
- data/examples/sprites/apple/divider.png +0 -0
- data/examples/sprites/apple/downloads.png +0 -0
- data/examples/sprites/apple/fragment.css +63 -0
- data/examples/sprites/apple/iphone.png +0 -0
- data/examples/sprites/apple/itunes.png +0 -0
- data/examples/sprites/apple/mac.png +0 -0
- data/examples/sprites/apple/search.png +0 -0
- data/examples/sprites/apple/sprite.png +0 -0
- data/examples/sprites/apple/store.png +0 -0
- data/examples/sprites/apple/support.png +0 -0
- data/examples/sprites/fragment.css +0 -0
- data/examples/sprites/index.html +33 -0
- data/examples/sprites/server.rb +10 -0
- data/examples/sprites/sprite.css +91 -0
- data/examples/sprites/words/fragment.css +28 -0
- data/examples/sprites/words/latitude.png +0 -0
- data/examples/sprites/words/of.png +0 -0
- data/examples/sprites/words/set.png +0 -0
- data/examples/sprites/words/specified.png +0 -0
- data/examples/sprites/words/sprite.css +24 -0
- data/examples/sprites/words/sprite.png +0 -0
- data/lib/spittle/chunk.rb +12 -0
- data/lib/spittle/directory_spriter.rb +63 -0
- data/lib/spittle/file_header.rb +7 -0
- data/lib/spittle/filters.rb +64 -0
- data/lib/spittle/idat.rb +26 -0
- data/lib/spittle/iend.rb +9 -0
- data/lib/spittle/ihdr.rb +30 -0
- data/lib/spittle/image.rb +114 -0
- data/lib/spittle/parser.rb +54 -0
- data/lib/spittle/processor.rb +28 -0
- data/lib/spittle/sprite.rb +39 -0
- data/lib/spittle/stylesheet_builder.rb +22 -0
- data/lib/spittle.rb +16 -0
- data/spec/builders/image_builder.rb +22 -0
- data/spec/css_fragments/deep/style/fragment.css +1 -0
- data/spec/css_fragments/some/fragment.css +1 -0
- data/spec/expected_output/merge_right_test.png +0 -0
- data/spec/expected_output/write_test.png +0 -0
- data/spec/images/lightening.png +0 -0
- data/spec/integration_spec.rb +134 -0
- data/spec/lib/file_header_spec.rb +10 -0
- data/spec/lib/idat_spec.rb +30 -0
- data/spec/lib/ihdr_spec.rb +43 -0
- data/spec/lib/image_spec.rb +19 -0
- data/spec/lib/parser_spec.rb +12 -0
- data/spec/lib/sprite_spec.rb +36 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/sprite_dirs/words/latitude.png +0 -0
- data/spec/sprite_dirs/words/of.png +0 -0
- data/spec/sprite_dirs/words/set.png +0 -0
- data/spec/sprite_dirs/words/specified.png +0 -0
- data/spec/tmp/merge_right_test.png +0 -0
- data/spec/tmp/write_test.png +0 -0
- metadata +137 -0
data/.gitignore
ADDED
data/README
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
[ PNG, PNG, PNG ] (°_°)
|
2
|
+
[ PNG, PNG, PNG ] (° )
|
3
|
+
[ PNG, PNG, PNG ] )°)
|
4
|
+
[ PNG, PNG, )°)
|
5
|
+
[ PNG, )°)
|
6
|
+
[ )°)
|
7
|
+
|
8
|
+
\(°_°)/ -> SPRITES!!!
|
9
|
+
|
10
|
+
|
11
|
+
It takes your PNG's, chews them up and spits out sprites!
|
12
|
+
|
13
|
+
point bin/spittle at a directory, and watch it sprite away!
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
currently only supports images of the same height - this will change soon.
|
18
|
+
|
19
|
+
thx to tjennings for the initial spike and help
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "spittle"
|
8
|
+
gem.summary = %Q{pure ruby PNG}
|
9
|
+
gem.description = %Q{pure ruby PNG}
|
10
|
+
gem.email = ["qzzzq1@gmail.com", "tyler.jennings@gmail.com"]
|
11
|
+
gem.homepage = "http://github.com/aberant/spittle"
|
12
|
+
gem.authors = ["aberant", "tjennings"]
|
13
|
+
gem.add_development_dependency "rspec" #, ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec #=> :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "spittle #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.0
|
data/bin/spittle
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + "/../lib/spittle.rb"
|
4
|
+
|
5
|
+
dir = ARGV[0]
|
6
|
+
|
7
|
+
if dir
|
8
|
+
Spittle::Processor.new(:source => dir).write
|
9
|
+
else
|
10
|
+
puts
|
11
|
+
puts "spittle! it chews up your PNG's and spits out sprites!"
|
12
|
+
puts "useage: spittle DIRECTORY"
|
13
|
+
puts "eg. spittle my_images"
|
14
|
+
puts
|
15
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
The sprites here are pre generated. If you want to see it work yourself delete the the two sprite.png files and all the *.css. Then simply run '../bin/spittle' and it should regenreate the sprites.
|
2
|
+
|
3
|
+
The server script will start a WEBrick server on port 3000 and serve from this directory. If everything worked out you should see the two sprite samples displayed in index.html.
|
4
|
+
|
5
|
+
.
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,63 @@
|
|
1
|
+
.apple_itunes {
|
2
|
+
background: transparent url(/apple/sprite.png) -350px 0px no-repeat;
|
3
|
+
width:116;
|
4
|
+
height:38;
|
5
|
+
text-indent:-5000px;
|
6
|
+
}
|
7
|
+
|
8
|
+
.apple_mac {
|
9
|
+
background: transparent url(/apple/sprite.png) -466px 0px no-repeat;
|
10
|
+
width:116;
|
11
|
+
height:38;
|
12
|
+
text-indent:-5000px;
|
13
|
+
}
|
14
|
+
|
15
|
+
.apple_apple {
|
16
|
+
background: transparent url(/apple/sprite.png) 0px 0px no-repeat;
|
17
|
+
width:117;
|
18
|
+
height:38;
|
19
|
+
text-indent:-5000px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.apple_store {
|
23
|
+
background: transparent url(/apple/sprite.png) -744px 0px no-repeat;
|
24
|
+
width:116;
|
25
|
+
height:38;
|
26
|
+
text-indent:-5000px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.apple_search {
|
30
|
+
background: transparent url(/apple/sprite.png) -582px 0px no-repeat;
|
31
|
+
width:162;
|
32
|
+
height:38;
|
33
|
+
text-indent:-5000px;
|
34
|
+
}
|
35
|
+
|
36
|
+
.apple_divider {
|
37
|
+
background: transparent url(/apple/sprite.png) -117px 0px no-repeat;
|
38
|
+
width:1;
|
39
|
+
height:38;
|
40
|
+
text-indent:-5000px;
|
41
|
+
}
|
42
|
+
|
43
|
+
.apple_support {
|
44
|
+
background: transparent url(/apple/sprite.png) -860px 0px no-repeat;
|
45
|
+
width:116;
|
46
|
+
height:38;
|
47
|
+
text-indent:-5000px;
|
48
|
+
}
|
49
|
+
|
50
|
+
.apple_downloads {
|
51
|
+
background: transparent url(/apple/sprite.png) -118px 0px no-repeat;
|
52
|
+
width:116;
|
53
|
+
height:38;
|
54
|
+
text-indent:-5000px;
|
55
|
+
}
|
56
|
+
|
57
|
+
.apple_iphone {
|
58
|
+
background: transparent url(/apple/sprite.png) -234px 0px no-repeat;
|
59
|
+
width:116;
|
60
|
+
height:38;
|
61
|
+
text-indent:-5000px;
|
62
|
+
}
|
63
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>A simple sprite test</title>
|
4
|
+
<link href="/sprite.css" type="text/css" rel="stylesheet" />
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<style>
|
8
|
+
.float_left {float:left}
|
9
|
+
.menu {height: 100px}
|
10
|
+
</style>
|
11
|
+
Hello. See spittle run:
|
12
|
+
<div class="words_of">of</div>
|
13
|
+
<div class="words_latitude">latitude</div>
|
14
|
+
<div class="words_set">set</div>
|
15
|
+
|
16
|
+
Some random menu bar
|
17
|
+
<div>
|
18
|
+
<span class="menu float_left apple_apple">apple</span>
|
19
|
+
<span class="menu float_left apple_divider"></span>
|
20
|
+
<span class="menu float_left apple_store">store</span>
|
21
|
+
<span class="menu float_left apple_divider"></span>
|
22
|
+
<span class="menu float_left apple_itunes">ipod</span>
|
23
|
+
<span class="menu float_left apple_divider"></span>
|
24
|
+
<span class="menu float_left apple_iphone">iphone</span>
|
25
|
+
<span class="menu float_left apple_divider"></span>
|
26
|
+
<span class="menu float_left apple_downloads">downloads</span>
|
27
|
+
<span class="menu float_left apple_divider"></span>
|
28
|
+
<span class="menu float_left apple_support">suport</span>
|
29
|
+
<span class="menu float_left apple_divider"></span>
|
30
|
+
<span class="menu float_left apple_search">search</span>
|
31
|
+
</div>
|
32
|
+
</body>
|
33
|
+
</html>
|
@@ -0,0 +1,91 @@
|
|
1
|
+
.apple_itunes {
|
2
|
+
background: transparent url(/apple/sprite.png) -350px 0px no-repeat;
|
3
|
+
width:116;
|
4
|
+
height:38;
|
5
|
+
text-indent:-5000px;
|
6
|
+
}
|
7
|
+
|
8
|
+
.apple_mac {
|
9
|
+
background: transparent url(/apple/sprite.png) -466px 0px no-repeat;
|
10
|
+
width:116;
|
11
|
+
height:38;
|
12
|
+
text-indent:-5000px;
|
13
|
+
}
|
14
|
+
|
15
|
+
.apple_apple {
|
16
|
+
background: transparent url(/apple/sprite.png) 0px 0px no-repeat;
|
17
|
+
width:117;
|
18
|
+
height:38;
|
19
|
+
text-indent:-5000px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.apple_store {
|
23
|
+
background: transparent url(/apple/sprite.png) -744px 0px no-repeat;
|
24
|
+
width:116;
|
25
|
+
height:38;
|
26
|
+
text-indent:-5000px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.apple_search {
|
30
|
+
background: transparent url(/apple/sprite.png) -582px 0px no-repeat;
|
31
|
+
width:162;
|
32
|
+
height:38;
|
33
|
+
text-indent:-5000px;
|
34
|
+
}
|
35
|
+
|
36
|
+
.apple_divider {
|
37
|
+
background: transparent url(/apple/sprite.png) -117px 0px no-repeat;
|
38
|
+
width:1;
|
39
|
+
height:38;
|
40
|
+
text-indent:-5000px;
|
41
|
+
}
|
42
|
+
|
43
|
+
.apple_support {
|
44
|
+
background: transparent url(/apple/sprite.png) -860px 0px no-repeat;
|
45
|
+
width:116;
|
46
|
+
height:38;
|
47
|
+
text-indent:-5000px;
|
48
|
+
}
|
49
|
+
|
50
|
+
.apple_downloads {
|
51
|
+
background: transparent url(/apple/sprite.png) -118px 0px no-repeat;
|
52
|
+
width:116;
|
53
|
+
height:38;
|
54
|
+
text-indent:-5000px;
|
55
|
+
}
|
56
|
+
|
57
|
+
.apple_iphone {
|
58
|
+
background: transparent url(/apple/sprite.png) -234px 0px no-repeat;
|
59
|
+
width:116;
|
60
|
+
height:38;
|
61
|
+
text-indent:-5000px;
|
62
|
+
}
|
63
|
+
|
64
|
+
.words_set {
|
65
|
+
background: transparent url(/words/sprite.png) -85px 0px no-repeat;
|
66
|
+
width:26;
|
67
|
+
height:21;
|
68
|
+
text-indent:-5000px;
|
69
|
+
}
|
70
|
+
|
71
|
+
.words_specified {
|
72
|
+
background: transparent url(/words/sprite.png) -111px 0px no-repeat;
|
73
|
+
width:70;
|
74
|
+
height:21;
|
75
|
+
text-indent:-5000px;
|
76
|
+
}
|
77
|
+
|
78
|
+
.words_latitude {
|
79
|
+
background: transparent url(/words/sprite.png) 0px 0px no-repeat;
|
80
|
+
width:66;
|
81
|
+
height:21;
|
82
|
+
text-indent:-5000px;
|
83
|
+
}
|
84
|
+
|
85
|
+
.words_of {
|
86
|
+
background: transparent url(/words/sprite.png) -66px 0px no-repeat;
|
87
|
+
width:19;
|
88
|
+
height:21;
|
89
|
+
text-indent:-5000px;
|
90
|
+
}
|
91
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.words_set {
|
2
|
+
background: transparent url(/words/sprite.png) -85px 0px no-repeat;
|
3
|
+
width:26;
|
4
|
+
height:21;
|
5
|
+
text-indent:-5000px;
|
6
|
+
}
|
7
|
+
|
8
|
+
.words_specified {
|
9
|
+
background: transparent url(/words/sprite.png) -111px 0px no-repeat;
|
10
|
+
width:70;
|
11
|
+
height:21;
|
12
|
+
text-indent:-5000px;
|
13
|
+
}
|
14
|
+
|
15
|
+
.words_latitude {
|
16
|
+
background: transparent url(/words/sprite.png) 0px 0px no-repeat;
|
17
|
+
width:66;
|
18
|
+
height:21;
|
19
|
+
text-indent:-5000px;
|
20
|
+
}
|
21
|
+
|
22
|
+
.words_of {
|
23
|
+
background: transparent url(/words/sprite.png) -66px 0px no-repeat;
|
24
|
+
width:19;
|
25
|
+
height:21;
|
26
|
+
text-indent:-5000px;
|
27
|
+
}
|
28
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
.words_of {
|
2
|
+
background: transparent url(/words/sprite.png) -66px 0px no-repeat;
|
3
|
+
width:19;
|
4
|
+
text-indent:-5000px;
|
5
|
+
}
|
6
|
+
|
7
|
+
.words_set {
|
8
|
+
background: transparent url(/words/sprite.png) -85px 0px no-repeat;
|
9
|
+
width:26;
|
10
|
+
text-indent:-5000px;
|
11
|
+
}
|
12
|
+
|
13
|
+
.words_specified {
|
14
|
+
background: transparent url(/words/sprite.png) -111px 0px no-repeat;
|
15
|
+
width:70;
|
16
|
+
text-indent:-5000px;
|
17
|
+
}
|
18
|
+
|
19
|
+
.words_latitude {
|
20
|
+
background: transparent url(/words/sprite.png) 0px 0px no-repeat;
|
21
|
+
width:66;
|
22
|
+
text-indent:-5000px;
|
23
|
+
}
|
24
|
+
|
Binary file
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module PNG
|
2
|
+
class Chunk
|
3
|
+
def chunk_name
|
4
|
+
raise "looks like you havn't subclassed and defined a chunk_name"
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_chunk
|
8
|
+
to_check = chunk_name + encode
|
9
|
+
[encode.length].pack("N") + to_check + [Zlib.crc32(to_check)].pack("N")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class DirectoryProcessor
|
2
|
+
def initialize(dir)
|
3
|
+
@dir = dir
|
4
|
+
files = images
|
5
|
+
@sprite = PNG::Sprite.new
|
6
|
+
files.each {|f| @sprite.append(PNG::Image.open(f))}
|
7
|
+
end
|
8
|
+
|
9
|
+
def images
|
10
|
+
Dir.glob(@dir + "/*.png").reject{|i| i.match /sprite\.png/}
|
11
|
+
end
|
12
|
+
|
13
|
+
def write
|
14
|
+
@sprite.write(sprite_file)
|
15
|
+
File.open(css_file, 'w') do |f|
|
16
|
+
f.write(css)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cleanup
|
21
|
+
File.delete(sprite_file) rescue {}
|
22
|
+
File.delete(css_file) rescue {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def sprite_file
|
26
|
+
@dir + "/sprite.png"
|
27
|
+
end
|
28
|
+
|
29
|
+
def css_file
|
30
|
+
@dir + "/fragment.css"
|
31
|
+
end
|
32
|
+
|
33
|
+
def dir_name
|
34
|
+
@dir.split('/').last
|
35
|
+
end
|
36
|
+
|
37
|
+
def image_loc
|
38
|
+
#TODO: Lame!
|
39
|
+
("/" + @dir + "/sprite.png").gsub("/./", "/")
|
40
|
+
end
|
41
|
+
|
42
|
+
FRAG = <<-EOF
|
43
|
+
.<name>_<image_name> {
|
44
|
+
background: transparent url(<image_loc>) <offset>px 0px no-repeat;
|
45
|
+
width:<width>;
|
46
|
+
height:<height>;
|
47
|
+
text-indent:-5000px;
|
48
|
+
}
|
49
|
+
|
50
|
+
EOF
|
51
|
+
|
52
|
+
def css
|
53
|
+
@sprite.locations.inject("") do |out, image|
|
54
|
+
image_name, properties = image
|
55
|
+
out << FRAG.gsub("<name>", dir_name).
|
56
|
+
gsub("<image_name>", image_name.to_s).
|
57
|
+
gsub("<width>", properties[:width].to_s).
|
58
|
+
gsub("<height>", properties[:height].to_s).
|
59
|
+
gsub("<offset>", properties[:x].to_s).
|
60
|
+
gsub("<image_loc>", image_loc)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module PNG
|
2
|
+
class Filters
|
3
|
+
class << self
|
4
|
+
#TODO: feature envy, this behavior belongs to a row.
|
5
|
+
def fetch_pixel(idx, row)
|
6
|
+
return 0 if idx < 0
|
7
|
+
return row[idx] || 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def call( filter_type, value, index, row, last_row, record_width )
|
11
|
+
case filter_type
|
12
|
+
when 0
|
13
|
+
no_filter( value, index, row, last_row, record_width )
|
14
|
+
when 1
|
15
|
+
left( value, index, row, last_row, record_width )
|
16
|
+
when 2
|
17
|
+
up( value, index, row, last_row, record_width )
|
18
|
+
when 3
|
19
|
+
avg( value, index, row, last_row, record_width )
|
20
|
+
when 4
|
21
|
+
paeth( value, index, row, last_row, record_width )
|
22
|
+
else
|
23
|
+
raise "Invalid filter type (#{filter_type})"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def no_filter( value, index, row, last_row, record_width )
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def left( value, index, row, last_row, record_width )
|
32
|
+
(value + fetch_pixel(index - record_width, row)) % 256
|
33
|
+
end
|
34
|
+
|
35
|
+
def up( value, index, row, last_row, record_width )
|
36
|
+
(value + fetch_pixel(index, last_row)) % 256
|
37
|
+
end
|
38
|
+
|
39
|
+
def avg( value, index, row, last_row, record_width )
|
40
|
+
(value + ( (fetch_pixel(index - record_width, row) + fetch_pixel(index, last_row)) / 2 ).floor) % 256
|
41
|
+
end
|
42
|
+
|
43
|
+
def paeth( value, index, row, last_row, record_width )
|
44
|
+
a = fetch_pixel(index - record_width, row)
|
45
|
+
b = fetch_pixel(index, last_row)
|
46
|
+
c = fetch_pixel(index - record_width, last_row)
|
47
|
+
p = a + b - c
|
48
|
+
pa = (p - a).abs
|
49
|
+
pb = (p - b).abs
|
50
|
+
pc = (p - c).abs
|
51
|
+
|
52
|
+
pr = c
|
53
|
+
if ( pa <= pb and pa <= pc)
|
54
|
+
pr = a
|
55
|
+
elsif (pb <= pc)
|
56
|
+
pr = b
|
57
|
+
end
|
58
|
+
|
59
|
+
(value + pr) % 256
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/spittle/idat.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module PNG
|
2
|
+
class IDAT < Chunk
|
3
|
+
# I don't like that @compressed contains different values depending on how you're using it
|
4
|
+
# maybe we should introduce a builder?
|
5
|
+
def initialize( uncompressed="" )
|
6
|
+
@compressed = ""
|
7
|
+
@compressed += Zlib::Deflate.deflate( uncompressed.pack("C*") ) unless uncompressed == ""
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<( data )
|
11
|
+
@compressed << data
|
12
|
+
end
|
13
|
+
|
14
|
+
def encode
|
15
|
+
@compressed
|
16
|
+
end
|
17
|
+
|
18
|
+
def uncompressed
|
19
|
+
@uncompressed ||= Zlib::Inflate.inflate( @compressed ).unpack("C*")
|
20
|
+
end
|
21
|
+
|
22
|
+
def chunk_name
|
23
|
+
"IDAT"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/spittle/iend.rb
ADDED
data/lib/spittle/ihdr.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module PNG
|
2
|
+
class IHDR < Chunk
|
3
|
+
attr_accessor :width, :height, :depth, :color_type
|
4
|
+
# attr_accessor :compression_method, :filter_method, :interlace_method
|
5
|
+
|
6
|
+
def self.new_from_raw( data )
|
7
|
+
raw = data.unpack("N2C5")
|
8
|
+
|
9
|
+
new( *raw[0..3] )
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize( width, height, depth=8, color_type=2 )
|
13
|
+
raise "for now, spittle only supports images with a bit depth of 8" unless depth == 8
|
14
|
+
raise "for now, spittle only supports color type 2 or 6" unless color_type == 2 || color_type == 6
|
15
|
+
@width, @height, @depth, @color_type = width, height, depth, color_type
|
16
|
+
end
|
17
|
+
|
18
|
+
def encode
|
19
|
+
to_a.pack("N2C5")
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
[@width, @height, @depth, @color_type, 0, 0, 0]
|
24
|
+
end
|
25
|
+
|
26
|
+
def chunk_name
|
27
|
+
"IHDR"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|