chunky_png 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@ module ChunkyPNG
3
3
  # The Datastream class represents a PNG formatted datastream. It supports
4
4
  # both reading from and writing to strings, streams and files.
5
5
  #
6
- # A PNG datastream begins with the PNG signature, and than contains multiple
6
+ # A PNG datastream begins with the PNG signature, and then contains multiple
7
7
  # chunks, starting with a header (IHDR) chunk and finishing with an end
8
8
  # (IEND) chunk.
9
9
  #
@@ -1,24 +1,23 @@
1
1
  module ChunkyPNG
2
-
3
2
  # A palette describes the set of colors that is being used for an image.
4
3
  #
5
4
  # A PNG image can contain an explicit palette which defines the colors of
6
- # that image, but can also use an implicit palette, e.g. all truecolor
7
- # colors or all grayscale colors.
5
+ # that image, but can also use an implicit palette, e.g. all truecolor colors
6
+ # or all grayscale colors.
8
7
  #
9
- # This palette supports decoding colors from a palette if an explicit
10
- # palette is provided in a PNG datastream, and it supports encoding colors
11
- # to an explicit palette (stores as PLTE & tRNS chunks in a PNG file).
8
+ # This palette supports decoding colors from a palette if an explicit palette
9
+ # is provided in a PNG datastream, and it supports encoding colors to an
10
+ # explicit palette (stores as PLTE & tRNS chunks in a PNG file).
12
11
  #
13
12
  # @see ChunkyPNG::Color
14
13
  class Palette < SortedSet
15
-
16
14
  # Builds a new palette given a set (Enumerable instance) of colors.
17
15
  #
18
- # @param [Enumerable<Integer>] enum The set of colors to include in this palette.
19
- # This Enumerable can contains duplicates.
20
- # @param [Array] decoding_map An array of colors in the exact order at which
21
- # they appeared in the palette chunk, so that this array can be used for decoding.
16
+ # @param enum [Enumerable<Integer>] The set of colors to include in this
17
+ # palette.This Enumerable can contain duplicates.
18
+ # @param decoding_map [Array] An array of colors in the exact order at
19
+ # which they appeared in the palette chunk, so that this array can be
20
+ # used for decoding.
22
21
  def initialize(enum, decoding_map = nil)
23
22
  super(enum)
24
23
  @decoding_map = decoding_map if decoding_map
@@ -29,8 +28,10 @@ module ChunkyPNG
29
28
  #
30
29
  # This method will cerate a palette that is suitable for decoding an image.
31
30
  #
32
- # @param [ChunkyPNG::Chunk::Palette] The palette chunk to load from
33
- # @param [ChunkyPNG::Chunk::Transparency, nil] The optional transparency chunk.
31
+ # @param palette_chunk [ChunkyPNG::Chunk::Palette] The palette chunk to
32
+ # load from
33
+ # @param transparency_chunk [ChunkyPNG::Chunk::Transparency, nil] The
34
+ # optional transparency chunk.
34
35
  # @return [ChunkyPNG::Palette] The loaded palette instance.
35
36
  # @see ChunkyPNG::Palette#can_decode?
36
37
  def self.from_chunks(palette_chunk, transparency_chunk = nil)
@@ -53,25 +54,30 @@ module ChunkyPNG
53
54
  index += 1
54
55
  end
55
56
 
56
- self.new(decoding_map, decoding_map)
57
+ new(decoding_map, decoding_map)
57
58
  end
58
59
 
59
60
  # Builds a palette instance from a given canvas.
60
- # @param [ChunkyPNG::Canvas] canvas The canvas to create a palette for.
61
+ # @param canvas [ChunkyPNG::Canvas] The canvas to create a palette for.
61
62
  # @return [ChunkyPNG::Palette] The palette instance.
62
63
  def self.from_canvas(canvas)
63
- self.new(canvas.pixels)
64
+ # Although we don't need to call .uniq.sort before initializing, because
65
+ # Palette subclasses SortedSet, we get significantly better performance
66
+ # by doing so.
67
+ new(canvas.pixels.uniq.sort)
64
68
  end
65
69
 
66
70
  # Builds a palette instance from a given set of pixels.
67
- # @param [Enumerable<Integer>] pixels An enumeration of pixels to create a palette for
71
+ # @param pixels [Enumerable<Integer>] An enumeration of pixels to create a
72
+ # palette for
68
73
  # @return [ChunkyPNG::Palette] The palette instance.
69
74
  def self.from_pixels(pixels)
70
- self.new(pixels)
75
+ new(pixels)
71
76
  end
72
77
 
73
78
  # Checks whether the size of this palette is suitable for indexed storage.
74
- # @return [true, false] True if the number of colors in this palette is at most 256.
79
+ # @return [true, false] True if the number of colors in this palette is at
80
+ # most 256.
75
81
  def indexable?
76
82
  size <= 256
77
83
  end
@@ -84,56 +90,67 @@ module ChunkyPNG
84
90
  end
85
91
 
86
92
  # Check whether this palette only contains grayscale colors.
87
- # @return [true, false] True if all colors in this palette are grayscale teints.
93
+ # @return [true, false] True if all colors in this palette are grayscale
94
+ # teints.
88
95
  # @see ChunkyPNG::Color#grayscale??
89
96
  def grayscale?
90
97
  all? { |color| Color.grayscale?(color) }
91
98
  end
92
99
 
93
100
  # Check whether this palette only contains bacl and white.
94
- # @return [true, false] True if all colors in this palette are grayscale teints.
101
+ # @return [true, false] True if all colors in this palette are grayscale
102
+ # teints.
95
103
  # @see ChunkyPNG::Color#grayscale??
96
104
  def black_and_white?
97
105
  entries == [ChunkyPNG::Color::BLACK, ChunkyPNG::Color::WHITE]
98
106
  end
99
-
100
- # Returns a palette with all the opaque variants of the colors in this palette.
101
- # @return [ChunkyPNG::Palette] A new Palette instance with only opaque colors.
107
+
108
+ # Returns a palette with all the opaque variants of the colors in this
109
+ # palette.
110
+ # @return [ChunkyPNG::Palette] A new Palette instance with only opaque
111
+ # colors.
102
112
  # @see ChunkyPNG::Color#opaque!
103
113
  def opaque_palette
104
114
  self.class.new(map { |c| ChunkyPNG::Color.opaque!(c) })
105
115
  end
106
116
 
107
- # Checks whether this palette is suitable for decoding an image from a datastream.
117
+ # Checks whether this palette is suitable for decoding an image from a
118
+ # datastream.
108
119
  #
109
- # This requires that the positions of the colors in the original palette chunk is known,
110
- # which is stored as an array in the +@decoding_map+ instance variable.
120
+ # This requires that the positions of the colors in the original palette
121
+ # chunk is known, which is stored as an array in the +@decoding_map+
122
+ # instance variable.
111
123
  #
112
- # @return [true, false] True if a decoding map was built when this palette was loaded.
124
+ # @return [true, false] True if a decoding map was built when this palette
125
+ # was loaded.
113
126
  def can_decode?
114
127
  !@decoding_map.nil?
115
128
  end
116
129
 
117
- # Checks whether this palette is suitable for encoding an image from to datastream.
130
+ # Checks whether this palette is suitable for encoding an image from to
131
+ # datastream.
118
132
  #
119
- # This requires that the position of the color in the future palette chunk is known,
120
- # which is stored as a hash in the +@encoding_map+ instance variable.
133
+ # This requires that the position of the color in the future palette chunk
134
+ # is known, which is stored as a hash in the +@encoding_map+ instance
135
+ # variable.
121
136
  #
122
- # @return [true, false] True if a encoding map was built when this palette was loaded.
137
+ # @return [true, false] True if a encoding map was built when this palette
138
+ # was loaded.
123
139
  def can_encode?
124
140
  !@encoding_map.nil?
125
141
  end
126
142
 
127
143
  # Returns a color, given the position in the original palette chunk.
128
- # @param [Integer] index The 0-based position of the color in the palette.
129
- # @return [ChunkyPNG::Color] The color that is stored in the palette under the given index
144
+ # @param index [Integer] The 0-based position of the color in the palette.
145
+ # @return [ChunkyPNG::Color] The color that is stored in the palette under
146
+ # the given index
130
147
  # @see ChunkyPNG::Palette#can_decode?
131
148
  def [](index)
132
149
  @decoding_map[index]
133
150
  end
134
151
 
135
152
  # Returns the position of a color in the palette
136
- # @param [ChunkyPNG::Color] color The color for which to look up the index.
153
+ # @param color [ChunkyPNG::Color] The color for which to look up the index.
137
154
  # @return [Integer] The 0-based position of the color in the palette.
138
155
  # @see ChunkyPNG::Palette#can_encode?
139
156
  def index(color)
@@ -151,12 +168,12 @@ module ChunkyPNG
151
168
  ChunkyPNG::Chunk::Transparency.new('tRNS', map { |c| ChunkyPNG::Color.a(c) }.pack('C*'))
152
169
  end
153
170
 
154
- # Creates a PLTE chunk that corresponds with this palette to store the
155
- # r, g and b channels of all colors.
171
+ # Creates a PLTE chunk that corresponds with this palette to store the r,
172
+ # g, and b channels of all colors.
156
173
  #
157
- # Note that a PLTE chunk should only be included if the image is
158
- # encoded using index colors. After this chunk has been built, the
159
- # palette becomes suitable for encoding an image.
174
+ # @note A PLTE chunk should only be included if the image is encoded using
175
+ # index colors. After this chunk has been built, the palette becomes
176
+ # suitable for encoding an image.
160
177
  #
161
178
  # @return [ChunkyPNG::Chunk::Palette] The PLTE chunk.
162
179
  # @see ChunkyPNG::Palette#can_encode?
@@ -174,7 +191,7 @@ module ChunkyPNG
174
191
 
175
192
  # Determines the most suitable colormode for this palette.
176
193
  # @return [Integer] The colormode which would create the smallest possible
177
- # file for images that use this exact palette.
194
+ # file for images that use this exact palette.
178
195
  def best_color_settings
179
196
  if black_and_white?
180
197
  [ChunkyPNG::COLOR_GRAYSCALE, 1]
@@ -192,17 +209,17 @@ module ChunkyPNG
192
209
  [ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 8]
193
210
  end
194
211
  end
195
-
212
+
196
213
  # Determines the minimal bit depth required for an indexed image
197
- # @return [Integer] Number of bits per pixel, i.e. 1, 2, 4 or 8, or nil if this
198
- # image cannot be saved as an indexed image.
214
+ # @return [Integer] Number of bits per pixel, i.e. 1, 2, 4 or 8, or nil if
215
+ # this image cannot be saved as an indexed image.
199
216
  def determine_bit_depth
200
217
  case size
201
- when 1..2; 1
202
- when 3..4; 2
203
- when 5..16; 4
204
- when 17..256; 8
205
- else nil
218
+ when 1..2 then 1
219
+ when 3..4 then 2
220
+ when 5..16 then 4
221
+ when 17..256 then 8
222
+ else nil
206
223
  end
207
224
  end
208
225
  end
@@ -1,5 +1,5 @@
1
1
  module ChunkyPNG
2
2
  # The current version of ChunkyPNG.
3
3
  # Set it and commit the change this before running rake release.
4
- VERSION = "1.3.0"
4
+ VERSION = "1.3.1"
5
5
  end
@@ -11,6 +11,15 @@ describe ChunkyPNG::Canvas do
11
11
  end
12
12
  end
13
13
 
14
+ describe '.from_bgr_stream' do
15
+ it "should load an image correctly from a datastream" do
16
+ File.open(resource_file('pixelstream.bgr')) do |stream|
17
+ matrix = ChunkyPNG::Canvas.from_bgr_stream(240, 180, stream)
18
+ matrix.should == reference_canvas('pixelstream_reference')
19
+ end
20
+ end
21
+ end
22
+
14
23
  describe '.from_rgba_stream' do
15
24
  it "should load an image correctly from a datastream" do
16
25
  File.open(resource_file('pixelstream.rgba')) do |stream|
@@ -1,20 +1,20 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'ChunyPNG.Color' do
4
- it "should interpret 4 arguments as RGBA values" do
4
+ it 'should interpret 4 arguments as RGBA values' do
5
5
  ChunkyPNG::Color(1, 2, 3, 4).should == ChunkyPNG::Color.rgba(1, 2, 3, 4)
6
6
  end
7
-
8
- it "should interpret 3 arguments as RGBA values" do
7
+
8
+ it 'should interpret 3 arguments as RGBA values' do
9
9
  ChunkyPNG::Color(1, 2, 3).should == ChunkyPNG::Color.rgb(1, 2, 3)
10
10
  end
11
-
12
- it "should interpret 2 arguments as a color to parse and an opacity value" do
11
+
12
+ it 'should interpret 2 arguments as a color to parse and an opacity value' do
13
13
  ChunkyPNG::Color('0x0a649664', 0xaa).should == 0x0a6496aa
14
14
  ChunkyPNG::Color('spring green @ 0.6666', 0xff).should == 0x00ff7fff
15
15
  end
16
-
17
- it "should interpret 1 argument as a color to parse" do
16
+
17
+ it 'should interpret 1 argument as a color to parse' do
18
18
  ChunkyPNG::Color.should_receive(:parse).with('0x0a649664')
19
19
  ChunkyPNG::Color('0x0a649664')
20
20
  end
@@ -30,55 +30,55 @@ describe ChunkyPNG::Color do
30
30
  @non_opaque = 0x0a649664
31
31
  @fully_transparent = 0x0a649600
32
32
  end
33
-
33
+
34
34
  describe '#parse' do
35
- it "should interpret a hex string correctly" do
35
+ it 'should interpret a hex string correctly' do
36
36
  parse('0x0a649664').should == ChunkyPNG::Color.from_hex('#0a649664')
37
37
  end
38
38
 
39
- it "should interpret a color name correctly" do
39
+ it 'should interpret a color name correctly' do
40
40
  parse(:spring_green).should == 0x00ff7fff
41
41
  parse('spring green').should == 0x00ff7fff
42
42
  parse('spring green @ 0.6666').should == 0x00ff7faa
43
43
  end
44
-
45
- it "should return numbers as is" do
44
+
45
+ it 'should return numbers as is' do
46
46
  parse('12345').should == 12345
47
47
  parse(12345).should == 12345
48
48
  end
49
49
  end
50
50
 
51
51
  describe '#pixel_bytesize' do
52
- it "should return the normal amount of bytes with a bit depth of 8" do
52
+ it 'should return the normal amount of bytes with a bit depth of 8' do
53
53
  pixel_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 8).should == 3
54
54
  end
55
55
 
56
- it "should return a multiple of the normal amount of bytes with a bit depth greater than 8" do
56
+ it 'should return a multiple of the normal amount of bytes with a bit depth greater than 8' do
57
57
  pixel_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 16).should == 6
58
58
  pixel_bytesize(ChunkyPNG::COLOR_TRUECOLOR_ALPHA, 16).should == 8
59
59
  pixel_bytesize(ChunkyPNG::COLOR_GRAYSCALE_ALPHA, 16).should == 4
60
60
  end
61
-
62
- it "should return 1 with a bit depth lower than 0" do
61
+
62
+ it 'should return 1 with a bit depth lower than 0' do
63
63
  pixel_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 4).should == 1
64
64
  pixel_bytesize(ChunkyPNG::COLOR_INDEXED, 2).should == 1
65
65
  pixel_bytesize(ChunkyPNG::COLOR_GRAYSCALE_ALPHA, 1).should == 1
66
66
  end
67
67
  end
68
-
68
+
69
69
  describe '#pass_bytesize' do
70
- it "should calculate a pass size correctly" do
70
+ it 'should calculate a pass size correctly' do
71
71
  pass_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 8, 10, 10).should == 310
72
72
  end
73
-
74
- it "should return 0 if one of the dimensions is zero" do
73
+
74
+ it 'should return 0 if one of the dimensions is zero' do
75
75
  pass_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 8, 0, 10).should == 0
76
76
  pass_bytesize(ChunkyPNG::COLOR_TRUECOLOR, 8, 10, 0).should == 0
77
77
  end
78
78
  end
79
79
 
80
80
  describe '#rgba' do
81
- it "should represent pixels as the correct number" do
81
+ it 'should represent pixels as the correct number' do
82
82
  rgba(255, 255, 255, 255).should == @white
83
83
  rgba( 0, 0, 0, 255).should == @black
84
84
  rgba( 10, 100, 150, 255).should == @opaque
@@ -86,9 +86,9 @@ describe ChunkyPNG::Color do
86
86
  rgba( 10, 100, 150, 0).should == @fully_transparent
87
87
  end
88
88
  end
89
-
89
+
90
90
  describe '#from_hex' do
91
- it "should load colors correctly from hex notation" do
91
+ it 'should load colors correctly from hex notation' do
92
92
  from_hex('0a649664').should == @non_opaque
93
93
  from_hex('#0a649664').should == @non_opaque
94
94
  from_hex('0x0a649664').should == @non_opaque
@@ -99,17 +99,17 @@ describe ChunkyPNG::Color do
99
99
  from_hex('#abc').should == 0xaabbccff
100
100
  from_hex('0xabc').should == 0xaabbccff
101
101
  end
102
-
103
- it "should allow setting opacity explicitly" do
102
+
103
+ it 'should allow setting opacity explicitly' do
104
104
  from_hex('0x0a6496', 0x64).should == @non_opaque
105
105
  from_hex('#0a6496', 0x64).should == @non_opaque
106
106
  from_hex('0xabc', 0xdd).should == 0xaabbccdd
107
107
  from_hex('#abc', 0xdd).should == 0xaabbccdd
108
108
  end
109
109
  end
110
-
110
+
111
111
  describe '#html_color' do
112
- it "should find the correct color value" do
112
+ it 'should find the correct color value' do
113
113
  html_color(:springgreen).should == 0x00ff7fff
114
114
  html_color(:spring_green).should == 0x00ff7fff
115
115
  html_color('springgreen').should == 0x00ff7fff
@@ -117,26 +117,26 @@ describe ChunkyPNG::Color do
117
117
  html_color('SpringGreen').should == 0x00ff7fff
118
118
  html_color('SPRING_GREEN').should == 0x00ff7fff
119
119
  end
120
-
121
- it "should set the opacity level explicitly" do
120
+
121
+ it 'should set the opacity level explicitly' do
122
122
  html_color(:springgreen, 0xff).should == 0x00ff7fff
123
123
  html_color(:springgreen, 0xaa).should == 0x00ff7faa
124
124
  html_color(:springgreen, 0x00).should == 0x00ff7f00
125
125
  end
126
-
127
- it "should set opacity levels from the color name" do
126
+
127
+ it 'should set opacity levels from the color name' do
128
128
  html_color('Spring green @ 1.0').should == 0x00ff7fff
129
129
  html_color('Spring green @ 0.666').should == 0x00ff7faa
130
130
  html_color('Spring green @ 0.0').should == 0x00ff7f00
131
131
  end
132
-
133
- it "should raise for an unkown color name" do
132
+
133
+ it 'should raise for an unkown color name' do
134
134
  lambda { html_color(:nonsense) }.should raise_error(ArgumentError)
135
135
  end
136
136
  end
137
-
137
+
138
138
  describe '#opaque?' do
139
- it "should correctly check for opaqueness" do
139
+ it 'should correctly check for opaqueness' do
140
140
  opaque?(@white).should be_true
141
141
  opaque?(@black).should be_true
142
142
  opaque?(@opaque).should be_true
@@ -144,47 +144,47 @@ describe ChunkyPNG::Color do
144
144
  opaque?(@fully_transparent).should be_false
145
145
  end
146
146
  end
147
-
148
- describe 'extractiion of separate color channels' do
149
- it "should extract components from a color correctly" do
147
+
148
+ describe 'extraction of separate color channels' do
149
+ it 'should extract components from a color correctly' do
150
150
  r(@opaque).should == 10
151
151
  g(@opaque).should == 100
152
152
  b(@opaque).should == 150
153
153
  a(@opaque).should == 255
154
154
  end
155
155
  end
156
-
156
+
157
157
  describe '#grayscale_teint' do
158
- it "should calculate the correct grayscale teint" do
158
+ it 'should calculate the correct grayscale teint' do
159
159
  grayscale_teint(@opaque).should == 79
160
160
  grayscale_teint(@non_opaque).should == 79
161
161
  end
162
162
  end
163
-
163
+
164
164
  describe '#to_grayscale' do
165
- it "should use the grayscale teint for r, g and b" do
165
+ it 'should use the grayscale teint for r, g and b' do
166
166
  gs = to_grayscale(@non_opaque)
167
167
  r(gs).should == grayscale_teint(@non_opaque)
168
168
  g(gs).should == grayscale_teint(@non_opaque)
169
169
  b(gs).should == grayscale_teint(@non_opaque)
170
170
  end
171
-
172
- it "should preserve the alpha channel" do
171
+
172
+ it 'should preserve the alpha channel' do
173
173
  a(to_grayscale(@non_opaque)).should == a(@non_opaque)
174
174
  a(to_grayscale(@opaque)).should == ChunkyPNG::Color::MAX
175
175
  end
176
176
  end
177
-
177
+
178
178
  describe '#to_hex' do
179
- it "should represent colors correcly using hex notation" do
179
+ it 'should represent colors correcly using hex notation' do
180
180
  to_hex(@white).should == '#ffffffff'
181
181
  to_hex(@black).should == '#000000ff'
182
182
  to_hex(@opaque).should == '#0a6496ff'
183
183
  to_hex(@non_opaque).should == '#0a649664'
184
184
  to_hex(@fully_transparent).should == '#0a649600'
185
185
  end
186
-
187
- it "should represent colors correcly using hex notation without alpha channel" do
186
+
187
+ it 'should represent colors correcly using hex notation without alpha channel' do
188
188
  to_hex(@white, false).should == '#ffffff'
189
189
  to_hex(@black, false).should == '#000000'
190
190
  to_hex(@opaque, false).should == '#0a6496'
@@ -194,58 +194,82 @@ describe ChunkyPNG::Color do
194
194
  end
195
195
 
196
196
  describe 'conversion to other formats' do
197
- it "should convert the individual color values back correctly" do
197
+ it 'should convert the individual color values back correctly' do
198
198
  to_truecolor_bytes(@opaque).should == [10, 100, 150]
199
199
  to_truecolor_alpha_bytes(@non_opaque).should == [10, 100, 150, 100]
200
200
  end
201
201
  end
202
-
202
+
203
203
  describe '#compose' do
204
204
 
205
- it "should use the foregorund color as is when the background color is fully transparent" do
205
+ it 'should use the foregorund color as is when the background color is fully transparent' do
206
206
  compose(@non_opaque, @fully_transparent).should == @non_opaque
207
207
  end
208
208
 
209
- it "should use the foregorund color as is when an opaque color is given as foreground color" do
209
+ it 'should use the foregorund color as is when an opaque color is given as foreground color' do
210
210
  compose(@opaque, @white).should == @opaque
211
211
  end
212
212
 
213
- it "should use the background color as is when a fully transparent pixel is given as foreground color" do
213
+ it 'should use the background color as is when a fully transparent pixel is given as foreground color' do
214
214
  compose(@fully_transparent, @white).should == @white
215
215
  end
216
216
 
217
- it "should compose pixels correctly with both algorithms" do
217
+ it 'should compose pixels correctly with both algorithms' do
218
218
  compose_quick(@non_opaque, @white).should == 0x9fc2d6ff
219
219
  compose_precise(@non_opaque, @white).should == 0x9fc2d6ff
220
220
  end
221
221
  end
222
-
222
+
223
223
  describe '#decompose_alpha' do
224
- it "should decompose the alpha channel correctly" do
224
+ it 'should decompose the alpha channel correctly' do
225
225
  decompose_alpha(0x9fc2d6ff, @opaque, @white).should == 0x00000064
226
226
  end
227
-
228
- it "should return fully transparent if the background channel matches the resulting color" do
227
+
228
+ it 'should return fully transparent if the background channel matches the resulting color' do
229
229
  decompose_alpha(0xabcdefff, 0xff000000, 0xabcdefff).should == 0x00
230
230
  end
231
-
232
- it "should return fully opaque if the background channel matches the mask color" do
231
+
232
+ it 'should return fully opaque if the background channel matches the mask color' do
233
233
  decompose_alpha(0xff000000, 0xabcdefff, 0xabcdefff).should == 0xff
234
234
  end
235
-
236
- it "should return fully opaque if the resulting color matches the mask color" do
235
+
236
+ it 'should return fully opaque if the resulting color matches the mask color' do
237
237
  decompose_alpha(0xabcdefff, 0xabcdefff, 0xffffffff).should == 255
238
- end
238
+ end
239
239
  end
240
-
240
+
241
241
  describe '#blend' do
242
- it "should blend colors correctly" do
242
+ it 'should blend colors correctly' do
243
243
  blend(@opaque, @black).should == 0x05324bff
244
244
  end
245
-
246
- it "should not matter what color is used as foreground, and what as background" do
245
+
246
+ it 'should not matter what color is used as foreground, and what as background' do
247
247
  blend(@opaque, @black).should == blend(@black, @opaque)
248
248
  end
249
249
  end
250
- end
251
250
 
251
+ describe '#euclidean_distance_rgba' do
252
+ subject { euclidean_distance_rgba(color_a, color_b) }
253
+
254
+ context 'with white and black' do
255
+ let(:color_a) { @white }
256
+ let(:color_b) { @black }
257
+
258
+ it { should == Math.sqrt(195_075) } # sqrt(255^2 * 3)
259
+ end
260
+
261
+ context 'with black and white' do
262
+ let(:color_a) { @black }
263
+ let(:color_b) { @white }
264
+
265
+ it { should == Math.sqrt(195_075) } # sqrt(255^2 * 3)
266
+ end
267
+
268
+ context 'with the same colors' do
269
+ let(:color_a) { @white }
270
+ let(:color_b) { @white }
271
+
272
+ it { should == 0 }
273
+ end
274
+ end
275
+ end