css-spriter 0.9.2 → 1.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.
@@ -1,26 +0,0 @@
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
@@ -1,9 +0,0 @@
1
- module PNG
2
- class IEND < Chunk
3
- def encode; "" end
4
-
5
- def chunk_name
6
- "IEND"
7
- end
8
- end
9
- end
@@ -1,34 +0,0 @@
1
- module PNG
2
- class IHDR < Chunk
3
- SUPPORTED_COLOR_TYPES = [2,3,6]
4
- attr_accessor :width, :height, :depth, :color_type
5
- # attr_accessor :compression_method, :filter_method, :interlace_method
6
-
7
- def self.new_from_raw( data )
8
- raw = data.unpack("N2C5")
9
-
10
- new( *raw[0..6] )
11
- end
12
-
13
- def initialize( width, height, depth=8, color_type=2, compression=0, filter=0, interlace=0 )
14
- raise "for now, css-spriter only supports non-interlaced images" unless interlace == 0
15
- raise "for now, css-spriter only supports images with a bit depth of 8" unless depth == 8
16
- unless SUPPORTED_COLOR_TYPES.include? color_type
17
- raise "for now, css-spriter only supports color types #{SUPPORTED_COLOR_TYPES.JOIN(',')} color type was #{color_type}"
18
- end
19
- @width, @height, @depth, @color_type = width, height, depth, color_type
20
- end
21
-
22
- def encode
23
- to_a.pack("N2C5")
24
- end
25
-
26
- def to_a
27
- [@width, @height, @depth, @color_type, 0, 0, 0]
28
- end
29
-
30
- def chunk_name
31
- "IHDR"
32
- end
33
- end
34
- end
@@ -1,153 +0,0 @@
1
- module PNG
2
- class Image
3
- #color types
4
- RGB = 2
5
- RGBA = 6
6
-
7
- class << self
8
- def image_data( file_name, options={} )
9
- image_options = {:rgba => true}.merge( options )
10
-
11
- png = open(file_name)
12
-
13
- return png.to_image unless image_options[:rgba]
14
- png.to_image.to_rgba
15
- end
16
-
17
- def open( file_name )
18
- name = File.basename( file_name, ".png" )
19
-
20
- File.open(file_name, "r") do |f|
21
- ihdr, idat = Parser.go!( f )
22
- Image.new( ihdr, idat, name )
23
- end
24
- end
25
-
26
- def write( file_name, data, options = {} )
27
- ihdr = PNG::IHDR.new(data.width, data.height, 8, color_type_of(data.pixel_width))
28
-
29
- Image.new(ihdr, nil, file_name, :rows => data).write( file_name, options)
30
- end
31
-
32
- def default_filter_type
33
- 4 # paeth
34
- end
35
-
36
- private # class methods
37
-
38
- def color_type_of(pixel_width)
39
- case pixel_width
40
- when 3
41
- RGB
42
- when 4
43
- RGBA
44
- end
45
- end
46
- end
47
-
48
- def initialize( ihdr, idat, name, options = {} )
49
- @ihdr = ihdr
50
- @idat = idat
51
- @name = name
52
- @rows = options[:rows]
53
- end
54
-
55
- attr_reader :name
56
- def width; @ihdr.width end
57
- def height; @ihdr.height end
58
- def depth; @ihdr.depth end
59
- def color_type; @ihdr.color_type end
60
- def uncompressed; @idat.uncompressed end
61
-
62
- def write(file_name, options={})
63
- filter_type = options[:filter_type] || Image.default_filter_type
64
- File.open(file_name, 'w') do |f|
65
- f.write(generate_png( filter_type ))
66
- end
67
- end
68
-
69
- # check for RGB or RGBA
70
- def pixel_width
71
- ( color_type == RGB ? 3 : 4)
72
- end
73
-
74
- def filter_encoded_rows(filter_type)
75
- out = Array.new(height)
76
- rows.each_with_index do |row, scanline|
77
- last_row = rows.last_scanline(scanline)
78
- out[scanline] = encode_row( row, last_row, filter_type, pixel_width)
79
- end
80
- out
81
- end
82
-
83
- def to_image
84
- uncompressed = @idat.uncompressed
85
-
86
- #scanline_width - 1 because we're stripping the filter bit
87
- n_out = CssSpriter::ImageData.new(:scanline_width => scanline_width - 1,
88
- :pixel_width => pixel_width,
89
- :name => self.name,
90
- :data => Array.new(height))
91
- offset = 0
92
- height.times do |scanline|
93
- end_row = scanline_width + offset
94
- row = uncompressed.slice(offset, scanline_width)
95
- n_out[scanline] = decode(scanline, row, n_out, pixel_width)
96
- offset = end_row
97
- end
98
- n_out
99
- end
100
-
101
- def to_s
102
- inspect
103
- end
104
-
105
- def inspect
106
- "#{@name} (#{height} x #{width}) [color type: #{color_type}, depth: #{depth}]"
107
- end
108
-
109
- private
110
-
111
- def scanline_width
112
- # + 1 adds filter byte
113
- (width * pixel_width) + 1
114
- end
115
-
116
- def rows
117
- @rows ||= to_image
118
- end
119
-
120
- def decode(current, row, data, pixel_width)
121
- filter_type = row.shift
122
- decode_row(row, data.last_scanline(current), filter_type, pixel_width)
123
- end
124
-
125
- def decode_row(row, last_scanline, filter_type, pixel_width)
126
- o = Array.new(row.size)
127
- row.each_with_index do |byte, i|
128
- o[i] = Filters.decode(filter_type, byte, i, o, last_scanline, pixel_width)
129
- end
130
- o
131
- end
132
-
133
- def encode_row( row, last_scanline, filter_type, pixel_width )
134
- o = Array.new(row.size)
135
- row.each_with_index do |byte, scanline|
136
- o[scanline] = Filters.encode( filter_type, byte, scanline, row, last_scanline, pixel_width)
137
- end
138
- o.unshift( filter_type )
139
- end
140
-
141
- def generate_png( filter_type )
142
- file_header = PNG::FileHeader.new.encode
143
- raw_data = filter_encoded_rows( filter_type )
144
- raw_data.flatten!
145
-
146
- ihdr = PNG::IHDR.new( width, height, depth, color_type ).to_chunk
147
- idat = PNG::IDAT.new( raw_data ).to_chunk
148
- iend = PNG::IEND.new.to_chunk
149
-
150
- file_header + ihdr + idat + iend
151
- end
152
- end
153
- end
@@ -1,54 +0,0 @@
1
- module PNG
2
- class Parser
3
- def self.go!(file)
4
- #TODO: Wanted to remove instance go! and use initialize, didn't work.
5
- #Weird
6
- Parser.new.go!(file)
7
- end
8
- def go!( file )
9
- check_header( file )
10
-
11
- while(not file.eof?) do
12
- parse_chunk(file)
13
- end
14
-
15
- [ @ihdr, @idat ]
16
- end
17
-
18
- private
19
- def check_header( file )
20
- header = file.read(8)
21
- raise "Invalid PNG file header" unless ( header == FileHeader.new.encode)
22
- end
23
-
24
- def parse_chunk(f)
25
- len = f.read(4).unpack("N")
26
- type = f.read(4)
27
- data = f.read(len[0])
28
- crc = f.read(4)
29
-
30
- raise "invalid CRC for chunk type #{type}" if crc_invalid?( type, data, crc )
31
-
32
- handle(type, data)
33
- end
34
-
35
- def handle(type, data)
36
- case(type)
37
- when "IHDR"
38
- @ihdr = PNG::IHDR.new_from_raw( data )
39
- @width, @height, @depth, @color_type = @ihdr.to_a
40
- when "IDAT"
41
- @idat ||= PNG::IDAT.new
42
- @idat << data
43
- when "IEND"
44
- # NOOP
45
- else
46
- #puts "Ignoring chunk type #{type}"
47
- end
48
- end
49
-
50
- def crc_invalid?( type, data, crc )
51
- [Zlib.crc32( type + data )] != crc.unpack("N")
52
- end
53
- end
54
- end
@@ -1,63 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe CssSpriter::ImageData do
4
- before do
5
- data = [[1,2,3],
6
- [4,5,6]]
7
- @id = CssSpriter::ImageData.new(:scanline_width => 3, :pixel_width => 3, :data => data)
8
- end
9
-
10
- it "can fill to a specified height" do
11
- result = @id.fill_to_height(3)
12
- result.should == [[1,2,3], [4,5,6], [0,0,0]]
13
- end
14
- it "has scanline width and pixel width attributes" do
15
- @id.scanline_width.should == 3
16
- @id.pixel_width.should == 3
17
- end
18
-
19
- it "can give you any arbitrary row in the data set" do
20
- @id[0].should == [1,2,3]
21
- @id.scanline(0).should == [1,2,3]
22
- end
23
-
24
- it "has an empty array by default" do
25
- id = CssSpriter::ImageData.new
26
- id.empty?.should be_true
27
- end
28
-
29
- it "should return nil when asked for an index that doesn't exist" do
30
- id = CssSpriter::ImageData.new
31
- id[0].should be_nil
32
- end
33
-
34
- it "can be assigned a row" do
35
- @id[0] = [1,2,3]
36
- @id[0].should == [1,2,3]
37
- end
38
-
39
- it "behaves like an array" do
40
- @id << [1,2,3]
41
- @id.last.should == [1,2,3]
42
-
43
- @id.size.should == 3
44
- end
45
-
46
- it "will return the last scanline given a current index" do
47
- @id.last_scanline(1).should == [1,2,3]
48
- end
49
-
50
- describe "RGBA conversion" do
51
- it "updates pixel width" do
52
- @id.to_rgba.pixel_width.should == 4 # RGBA pixel width
53
- end
54
-
55
- it "updates scanline width" do
56
- @id.to_rgba.scanline_width.should == 4
57
- end
58
-
59
- it "puts in an alpha byte with a default value of 255" do
60
- @id.to_rgba[0].should == [1,2,3,255]
61
- end
62
- end
63
- end
@@ -1,10 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe PNG::FileHeader do
4
- # the pnd header provides sanity checks against most common file transfer errrors
5
- it "outputs the PNG header" do
6
- header = PNG::FileHeader.new.encode
7
- header.should == [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
8
- end
9
- end
10
-
@@ -1,31 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe PNG::IDAT do
4
- before :each do
5
- # it's just "Hello, World!" encoded
6
- @data = "x\234\363H\315\311\311\327Q\b\317/\312IQ\004\000\037\236\004j"
7
- end
8
-
9
- it "accepts compressed data" do
10
- @idat = PNG::IDAT.new
11
-
12
- @idat << @data
13
-
14
- @idat.encode.should == @data
15
- end
16
-
17
- it "can chunk its self" do
18
- @idat = PNG::IDAT.new
19
- @idat << @data
20
- @chunk = chunk( "IDAT", @idat.encode )
21
-
22
- @idat.to_chunk.should == @chunk
23
- end
24
-
25
- it "accepts uncompressed data for it's constructor" do
26
- @idat = PNG::IDAT.new( "Hello, World!".unpack("C*") )
27
-
28
- @idat.encode.should == @data
29
- end
30
-
31
- end
@@ -1,43 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe PNG::IHDR do
4
- before :each do
5
- @width = 40
6
- @height = 40
7
- @bit_depth = 8
8
- @color_type = 2
9
-
10
- @raw = [@width, @height, @bit_depth, @color_type, 0, 0, 0].pack("N2C5")
11
- @chunk = chunk( "IHDR", @raw )
12
- end
13
-
14
- it "pulls out the width from the ihdr block" do
15
- @header = PNG::IHDR.new_from_raw( @raw )
16
- @header.width.should == @width
17
- end
18
-
19
- it "pulls out the height from the ihdr block" do
20
- @header = PNG::IHDR.new_from_raw( @raw )
21
- @header.height.should == @height
22
- end
23
-
24
- it "pulls out the bit depth from the ihdr block" do
25
- @header = PNG::IHDR.new_from_raw( @raw )
26
- @header.depth.should == @bit_depth
27
- end
28
-
29
- it "pulls out the color type from the ihdr block" do
30
- @header = PNG::IHDR.new_from_raw( @raw )
31
- @header.color_type.should == @color_type
32
- end
33
-
34
- it "encodes it's self properly" do
35
- @header = PNG::IHDR.new_from_raw( @raw )
36
- @header.encode.should == @raw
37
- end
38
-
39
- it "should be able to make a header chunk" do
40
- @header = PNG::IHDR.new_from_raw( @raw )
41
- @header.to_chunk.should == @chunk
42
- end
43
- end
@@ -1,42 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe PNG::Image do
4
- before :each do
5
- @sprite = Sprite.new
6
-
7
- @builder = ImageBuilder.new
8
-
9
- # 0 is the filter type for the row, then an RGB triplet since builder defaults to color type 2
10
- @image1 = @builder.build( :width => 1, :height => 1, :name => "image1", :data => [0,1,2,3] )
11
- @image2 = @builder.build( :width => 1, :height => 1, :name => "image2", :data => [0,4,5,6] )
12
- end
13
-
14
- it "can merge left" do
15
- result = @image1.to_image.merge_left @image2.to_image
16
-
17
- result.should == [[4,5,6,1,2,3]]
18
- end
19
-
20
- it "can encode the rows with filter 0" do
21
- @image1.filter_encoded_rows(0).should == [[0, 1, 2, 3]]
22
- end
23
-
24
-
25
- it "can encode the rows with filter 1" do
26
- image = @builder.build( :width => 2, :height => 1, :name => "image1", :data => [0,1,2,3,4,5,6] )
27
-
28
- # filter byte of 1
29
- # first byte of pixel 2 - pixel 1 is 3
30
- # second byte of pixel 2 - pixel 1 is 3.. etc
31
- image.filter_encoded_rows(1).should == [[1, 1, 2, 3, 3, 3, 3]]
32
- end
33
-
34
- it "can encode the rows with filter 2" do
35
- image = @builder.build( :width => 2, :height => 2, :name => "image1",
36
- :data => [0,1,2,3,4,5,6,
37
- 0,0,0,0,0,0,0])
38
- result = image
39
- # filter byte of 2
40
- result.filter_encoded_rows(2).should == [[2, 1, 2, 3, 4, 5, 6], [2, 255, 254, 253, 252, 251, 250]]
41
- end
42
- end