oily_png 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/Gemfile.lock +4 -4
- data/ext/oily_png/oily_png_ext.c +18 -2
- data/ext/oily_png/oily_png_ext.h +22 -2
- data/ext/oily_png/png_decoding.c +242 -71
- data/ext/oily_png/png_decoding.h +4 -1
- data/ext/oily_png/png_encoding.c +24 -23
- data/lib/oily_png.rb +1 -1
- data/oily_png.gemspec +4 -4
- data/spec/decoding_spec.rb +15 -42
- data/spec/encoding_spec.rb +3 -3
- data/spec/resources/basi0g01.png +0 -0
- data/spec/resources/basi0g02.png +0 -0
- data/spec/resources/basi0g04.png +0 -0
- data/spec/resources/basi0g08.png +0 -0
- data/spec/resources/basi0g16.png +0 -0
- data/spec/resources/basi2c08.png +0 -0
- data/spec/resources/basi2c16.png +0 -0
- data/spec/resources/basi3p01.png +0 -0
- data/spec/resources/basi3p02.png +0 -0
- data/spec/resources/basi3p04.png +0 -0
- data/spec/resources/basi3p08.png +0 -0
- data/spec/resources/basi4a08.png +0 -0
- data/spec/resources/basi4a16.png +0 -0
- data/spec/resources/basi6a08.png +0 -0
- data/spec/resources/basi6a16.png +0 -0
- data/spec/resources/basn0g01.png +0 -0
- data/spec/resources/basn0g02.png +0 -0
- data/spec/resources/basn0g04.png +0 -0
- data/spec/resources/basn0g08.png +0 -0
- data/spec/resources/basn0g16.png +0 -0
- data/spec/resources/basn2c08.png +0 -0
- data/spec/resources/basn2c16.png +0 -0
- data/spec/resources/basn3p01.png +0 -0
- data/spec/resources/basn3p02.png +0 -0
- data/spec/resources/basn3p04.png +0 -0
- data/spec/resources/basn3p08.png +0 -0
- data/spec/resources/basn4a08.png +0 -0
- data/spec/resources/basn4a16.png +0 -0
- data/spec/resources/basn6a08.png +0 -0
- data/spec/resources/basn6a16.png +0 -0
- data/spec/resources/s01i3p01.png +0 -0
- data/spec/resources/s01n3p01.png +0 -0
- data/spec/resources/s02i3p01.png +0 -0
- data/spec/resources/s02n3p01.png +0 -0
- data/spec/resources/s03i3p01.png +0 -0
- data/spec/resources/s03n3p01.png +0 -0
- data/spec/resources/s04i3p01.png +0 -0
- data/spec/resources/s04n3p01.png +0 -0
- data/spec/resources/s05i3p02.png +0 -0
- data/spec/resources/s05n3p02.png +0 -0
- data/spec/resources/s06i3p02.png +0 -0
- data/spec/resources/s06n3p02.png +0 -0
- data/spec/resources/s07i3p02.png +0 -0
- data/spec/resources/s07n3p02.png +0 -0
- data/spec/resources/s08i3p02.png +0 -0
- data/spec/resources/s08n3p02.png +0 -0
- data/spec/resources/s09i3p02.png +0 -0
- data/spec/resources/s09n3p02.png +0 -0
- data/spec/resources/s32i3p04.png +0 -0
- data/spec/resources/s32n3p04.png +0 -0
- data/spec/resources/s33i3p04.png +0 -0
- data/spec/resources/s33n3p04.png +0 -0
- data/spec/resources/s34i3p04.png +0 -0
- data/spec/resources/s34n3p04.png +0 -0
- data/spec/resources/s35i3p04.png +0 -0
- data/spec/resources/s35n3p04.png +0 -0
- data/spec/resources/s36i3p04.png +0 -0
- data/spec/resources/s36n3p04.png +0 -0
- data/spec/resources/s37i3p04.png +0 -0
- data/spec/resources/s37n3p04.png +0 -0
- data/spec/resources/s38i3p04.png +0 -0
- data/spec/resources/s38n3p04.png +0 -0
- data/spec/resources/s39i3p04.png +0 -0
- data/spec/resources/s39n3p04.png +0 -0
- data/spec/resources/s40i3p04.png +0 -0
- data/spec/resources/s40n3p04.png +0 -0
- data/spec/spec_helper.rb +10 -3
- metadata +83 -22
data/Gemfile
CHANGED
@@ -1,2 +1,10 @@
|
|
1
1
|
source :rubyforge
|
2
2
|
gemspec
|
3
|
+
|
4
|
+
# # Use the following gem specification instead of the 'gemspec' statement
|
5
|
+
# # to develop with a local chunky_png copy
|
6
|
+
|
7
|
+
# gem 'chunky_png', :path => File.expand_path('../chunky_png', File.dirname(__FILE__))
|
8
|
+
# gem 'oily_png', :path => File.dirname(__FILE__)
|
9
|
+
# gem 'rake'
|
10
|
+
# gem 'rspec'
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
oily_png (0.
|
5
|
-
chunky_png (~> 0.
|
4
|
+
oily_png (0.2.0)
|
5
|
+
chunky_png (~> 0.11)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
chunky_png (0.
|
10
|
+
chunky_png (0.11.0)
|
11
11
|
diff-lcs (1.1.2)
|
12
12
|
rake (0.8.7)
|
13
13
|
rspec (2.0.0)
|
@@ -25,7 +25,7 @@ PLATFORMS
|
|
25
25
|
ruby
|
26
26
|
|
27
27
|
DEPENDENCIES
|
28
|
-
chunky_png (~> 0.
|
28
|
+
chunky_png (~> 0.11)
|
29
29
|
oily_png!
|
30
30
|
rake
|
31
31
|
rspec (~> 2.0)
|
data/ext/oily_png/oily_png_ext.c
CHANGED
@@ -5,14 +5,14 @@ void Init_oily_png_ext() {
|
|
5
5
|
|
6
6
|
// Setup decoding
|
7
7
|
VALUE OilyPNG_PNGDecoding = rb_define_module_under(OilyPNG, "PNGDecoding");
|
8
|
-
rb_define_method(OilyPNG_PNGDecoding, "decode_png_image_pass", oily_png_decode_png_image_pass,
|
8
|
+
rb_define_method(OilyPNG_PNGDecoding, "decode_png_image_pass", oily_png_decode_png_image_pass, 6);
|
9
9
|
|
10
10
|
// Setup encoding
|
11
11
|
VALUE OilyPNG_PNGEncoding = rb_define_module_under(OilyPNG, "PNGEncoding");
|
12
12
|
rb_define_method(OilyPNG_PNGEncoding, "encode_png_image_pass_to_stream", oily_png_encode_png_image_pass_to_stream, 3);
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
char oily_png_samples_per_pixel(char color_mode) {
|
16
16
|
switch (color_mode) {
|
17
17
|
case OILY_PNG_COLOR_GRAYSCALE: return 1;
|
18
18
|
case OILY_PNG_COLOR_TRUECOLOR: return 3;
|
@@ -22,3 +22,19 @@ int oily_png_pixel_size(int color_mode) {
|
|
22
22
|
default: rb_raise(rb_eRuntimeError, "Unsupported color mode: %d", color_mode);
|
23
23
|
}
|
24
24
|
}
|
25
|
+
|
26
|
+
char oily_png_pixel_bitsize(char color_mode, char bit_depth) {
|
27
|
+
return oily_png_samples_per_pixel(color_mode) * bit_depth;
|
28
|
+
}
|
29
|
+
|
30
|
+
char oily_png_pixel_bytesize(char color_mode, char bit_depth) {
|
31
|
+
return (bit_depth < 8) ? 1 : (oily_png_pixel_bitsize(color_mode, bit_depth) + 7) >> 3;
|
32
|
+
}
|
33
|
+
|
34
|
+
long oily_png_scanline_bytesize(char color_mode, char bit_depth, long width) {
|
35
|
+
return (8 + ((oily_png_pixel_bitsize(color_mode, bit_depth) * width) + 7)) >> 3;
|
36
|
+
}
|
37
|
+
|
38
|
+
long oily_png_pass_bytesize(char color_mode, char bit_depth, long width, long height) {
|
39
|
+
return (width == 0 || height == 0) ? 0 : (oily_png_scanline_bytesize(color_mode, bit_depth, width)) * height;
|
40
|
+
}
|
data/ext/oily_png/oily_png_ext.h
CHANGED
@@ -37,8 +37,28 @@
|
|
37
37
|
void Init_oily_png_ext();
|
38
38
|
|
39
39
|
/*
|
40
|
-
Returns the number of
|
40
|
+
Returns the number of samples per pixel for a given color mode
|
41
41
|
*/
|
42
|
-
|
42
|
+
char oily_png_samples_per_pixel(char color_mode);
|
43
|
+
|
44
|
+
/*
|
45
|
+
Returns the number of bits per pixel for a given color mode and bit depth.
|
46
|
+
*/
|
47
|
+
char oily_png_pixel_bitsize(char color_mode, char bit_depth);
|
48
|
+
|
49
|
+
/*
|
50
|
+
Returns the number of bytes per pixel for a given color mode and bit depth.
|
51
|
+
*/
|
52
|
+
char oily_png_pixel_bytesize(char color_mode, char bit_depth);
|
53
|
+
|
54
|
+
/*
|
55
|
+
Returns the number of bytes per scanline for a given width, color mode and bit depth.
|
56
|
+
*/
|
57
|
+
long oily_png_scanline_bytesize(char color_mode, char bit_depth, long width);
|
58
|
+
|
59
|
+
/*
|
60
|
+
Returns the number of bytes in an image pass with the given properties.
|
61
|
+
*/
|
62
|
+
long oily_png_pass_bytesize(char color_mode, char bit_depth, long width, long height);
|
43
63
|
|
44
64
|
#endif
|
data/ext/oily_png/png_decoding.c
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
// Decodes a SUB filtered scanline at the given position in the byte array
|
5
|
-
void oily_png_decode_filter_sub(BYTE* bytes,
|
6
|
-
|
5
|
+
void oily_png_decode_filter_sub(BYTE* bytes, long pos, long line_length, char pixel_size) {
|
6
|
+
long i;
|
7
7
|
for (i = 1 + pixel_size; i < line_length; i++) {
|
8
8
|
UNFILTER_BYTE(bytes[pos + i], bytes[pos + i - pixel_size]);
|
9
9
|
}
|
10
10
|
}
|
11
11
|
|
12
12
|
// Decodes an UP filtered scanline at the given position in the byte array
|
13
|
-
void oily_png_decode_filter_up(BYTE* bytes,
|
14
|
-
|
13
|
+
void oily_png_decode_filter_up(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
14
|
+
long i;
|
15
15
|
// The first line is not filtered because there is no privous line
|
16
16
|
if (pos >= line_size) {
|
17
17
|
for (i = 1; i < line_size; i++) {
|
@@ -21,8 +21,8 @@ void oily_png_decode_filter_up(BYTE* bytes, int pos, int line_size, int pixel_si
|
|
21
21
|
}
|
22
22
|
|
23
23
|
// Decodes an AVERAGE filtered scanline at the given position in the byte array
|
24
|
-
void oily_png_decode_filter_average(BYTE* bytes,
|
25
|
-
|
24
|
+
void oily_png_decode_filter_average(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
25
|
+
long i;
|
26
26
|
BYTE a, b;
|
27
27
|
for (i = 1; i < line_size; i++) {
|
28
28
|
a = (i > pixel_size) ? bytes[pos + i - pixel_size] : 0;
|
@@ -32,103 +32,274 @@ void oily_png_decode_filter_average(BYTE* bytes, int pos, int line_size, int pix
|
|
32
32
|
}
|
33
33
|
|
34
34
|
// Decodes a PAETH filtered scanline at the given position in the byte array
|
35
|
-
void oily_png_decode_filter_paeth(BYTE* bytes,
|
35
|
+
void oily_png_decode_filter_paeth(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
36
36
|
BYTE a, b, c, pr;
|
37
|
-
|
37
|
+
long i, p, pa, pb, pc;
|
38
38
|
for (i = 1; i < line_size; i++) {
|
39
39
|
a = (i > pixel_size) ? bytes[pos + i - pixel_size] : 0;
|
40
40
|
b = (pos >= line_size) ? bytes[pos + i - line_size] : 0;
|
41
41
|
c = (pos >= line_size && i > pixel_size) ? bytes[pos + i - line_size - pixel_size] : 0;
|
42
42
|
p = a + b - c;
|
43
|
-
pa =
|
44
|
-
pb =
|
45
|
-
pc =
|
43
|
+
pa = (p > a) ? p - a : a - p;
|
44
|
+
pb = (p > b) ? p - b : b - p;
|
45
|
+
pc = (p > c) ? p - c : c - p;
|
46
46
|
pr = (pa <= pb) ? (pa <= pc ? a : c) : (pb <= pc ? b : c);
|
47
47
|
UNFILTER_BYTE(bytes[pos + i], pr);
|
48
48
|
}
|
49
49
|
}
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
BYTE oily_png_extract_1bit_element(BYTE* bytes, long start, long x) {
|
52
|
+
BYTE byte = bytes[start + 1 + (x >> 3)];
|
53
|
+
char bitshift = 7 - (x & (BYTE) 0x07);
|
54
|
+
return (byte & (0x01 << bitshift)) >> bitshift;
|
53
55
|
}
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
+
|
58
|
+
BYTE oily_png_extract_2bit_element(BYTE* bytes, long start, long x) {
|
59
|
+
BYTE byte = bytes[start + 1 + (x >> 2)];
|
60
|
+
char bitshift = (6 - ((x & (BYTE) 0x03) << 1));
|
61
|
+
return (byte & (0x03 << bitshift)) >> bitshift;
|
57
62
|
}
|
58
63
|
|
59
|
-
|
60
|
-
return (
|
64
|
+
BYTE oily_png_extract_4bit_element(BYTE* bytes, long start, long x) {
|
65
|
+
return ((x & 0x01) == 0) ? ((bytes[(start) + 1 + ((x) >> 1)] & (BYTE) 0xf0) >> 4) : (bytes[(start) + 1 + ((x) >> 1)] & (BYTE) 0x0f);
|
61
66
|
}
|
62
67
|
|
63
|
-
|
64
|
-
|
68
|
+
BYTE oily_png_resample_1bit_element(BYTE* bytes, long start, long x) {
|
69
|
+
BYTE value = oily_png_extract_1bit_element(bytes, start, x);
|
70
|
+
return (value == 0) ? 0x00 : 0xff;
|
65
71
|
}
|
66
72
|
|
67
|
-
|
68
|
-
|
73
|
+
BYTE oily_png_resample_2bit_element(BYTE* bytes, long start, long x) {
|
74
|
+
switch (oily_png_extract_2bit_element(bytes, start, x)) {
|
75
|
+
case 0x00: return 0x00;
|
76
|
+
case 0x01: return 0x55;
|
77
|
+
case 0x02: return 0xaa;
|
78
|
+
case 0x03: default: return 0xff;
|
79
|
+
}
|
69
80
|
}
|
70
81
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
82
|
+
BYTE oily_png_resample_4bit_element(BYTE* bytes, long start, long x) {
|
83
|
+
switch(oily_png_extract_4bit_element(bytes, start, x)) {
|
84
|
+
case 0x00: return 0;
|
85
|
+
case 0x01: return 17;
|
86
|
+
case 0x02: return 34;
|
87
|
+
case 0x03: return 51;
|
88
|
+
case 0x04: return 68;
|
89
|
+
case 0x05: return 85;
|
90
|
+
case 0x06: return 102;
|
91
|
+
case 0x07: return 119;
|
92
|
+
case 0x08: return 137;
|
93
|
+
case 0x09: return 154;
|
94
|
+
case 0x0a: return 171;
|
95
|
+
case 0x0b: return 188;
|
96
|
+
case 0x0c: return 205;
|
97
|
+
case 0x0d: return 222;
|
98
|
+
case 0x0e: return 239;
|
99
|
+
case 0x0f: default: return 255;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
PIXEL oily_png_decode_pixel_indexed_8bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
105
|
+
return (PIXEL) NUM2UINT(rb_funcall(decoding_palette, rb_intern("[]"), 1, INT2FIX(bytes[start + 1 + x])));
|
106
|
+
}
|
107
|
+
|
108
|
+
PIXEL oily_png_decode_pixel_indexed_4bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
109
|
+
return (PIXEL) NUM2UINT(rb_funcall(decoding_palette, rb_intern("[]"), 1, INT2FIX(oily_png_extract_4bit_element(bytes, start, x))));
|
110
|
+
}
|
111
|
+
|
112
|
+
PIXEL oily_png_decode_pixel_indexed_2bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
113
|
+
return (PIXEL) NUM2UINT(rb_funcall(decoding_palette, rb_intern("[]"), 1, INT2FIX(oily_png_extract_2bit_element(bytes, start, x))));
|
114
|
+
}
|
115
|
+
|
116
|
+
PIXEL oily_png_decode_pixel_indexed_1bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
117
|
+
return (PIXEL) NUM2UINT(rb_funcall(decoding_palette, rb_intern("[]"), 1, INT2FIX(oily_png_extract_1bit_element(bytes, start, x))));
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
PIXEL oily_png_decode_pixel_grayscale_8bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
122
|
+
return BUILD_PIXEL( bytes[start + 1 + x],
|
123
|
+
bytes[start + 1 + x],
|
124
|
+
bytes[start + 1 + x],
|
125
|
+
0xff);
|
126
|
+
}
|
127
|
+
|
128
|
+
PIXEL oily_png_decode_pixel_grayscale_1bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
129
|
+
return BUILD_PIXEL( oily_png_resample_1bit_element(bytes, start, x),
|
130
|
+
oily_png_resample_1bit_element(bytes, start, x),
|
131
|
+
oily_png_resample_1bit_element(bytes, start, x),
|
132
|
+
0xff);
|
133
|
+
}
|
134
|
+
|
135
|
+
PIXEL oily_png_decode_pixel_grayscale_2bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
136
|
+
return BUILD_PIXEL( oily_png_resample_2bit_element(bytes, start, x),
|
137
|
+
oily_png_resample_2bit_element(bytes, start, x),
|
138
|
+
oily_png_resample_2bit_element(bytes, start, x),
|
139
|
+
0xff);
|
140
|
+
}
|
141
|
+
|
142
|
+
PIXEL oily_png_decode_pixel_grayscale_4bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
143
|
+
return BUILD_PIXEL( oily_png_resample_4bit_element(bytes, start, x),
|
144
|
+
oily_png_resample_4bit_element(bytes, start, x),
|
145
|
+
oily_png_resample_4bit_element(bytes, start, x),
|
146
|
+
0xff);
|
147
|
+
}
|
148
|
+
|
149
|
+
PIXEL oily_png_decode_pixel_truecolor_8bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
150
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 3) + 0],
|
151
|
+
bytes[start + 1 + (x * 3) + 1],
|
152
|
+
bytes[start + 1 + (x * 3) + 2],
|
153
|
+
0xff);
|
154
|
+
}
|
155
|
+
|
156
|
+
PIXEL oily_png_decode_pixel_grayscale_alpha_8bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
157
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 2) + 0],
|
158
|
+
bytes[start + 1 + (x * 2) + 0],
|
159
|
+
bytes[start + 1 + (x * 2) + 0],
|
160
|
+
bytes[start + 1 + (x * 2) + 1]);
|
161
|
+
}
|
162
|
+
|
163
|
+
PIXEL oily_png_decode_pixel_truecolor_alpha_8bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
164
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 4) + 0],
|
165
|
+
bytes[start + 1 + (x * 4) + 1],
|
166
|
+
bytes[start + 1 + (x * 4) + 2],
|
167
|
+
bytes[start + 1 + (x * 4) + 3]);
|
168
|
+
}
|
169
|
+
|
170
|
+
PIXEL oily_png_decode_pixel_grayscale_16bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
171
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 2)],
|
172
|
+
bytes[start + 1 + (x * 2)],
|
173
|
+
bytes[start + 1 + (x * 2)],
|
174
|
+
0xff);
|
175
|
+
}
|
176
|
+
|
177
|
+
PIXEL oily_png_decode_pixel_truecolor_16bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
178
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 6) + 0],
|
179
|
+
bytes[start + 1 + (x * 6) + 2],
|
180
|
+
bytes[start + 1 + (x * 6) + 4],
|
181
|
+
0xff);
|
182
|
+
}
|
183
|
+
|
184
|
+
PIXEL oily_png_decode_pixel_grayscale_alpha_16bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
185
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 4) + 0],
|
186
|
+
bytes[start + 1 + (x * 4) + 0],
|
187
|
+
bytes[start + 1 + (x * 4) + 0],
|
188
|
+
bytes[start + 1 + (x * 4) + 2]);
|
189
|
+
}
|
190
|
+
|
191
|
+
PIXEL oily_png_decode_pixel_truecolor_alpha_16bit(BYTE* bytes, long start, long x, VALUE decoding_palette) {
|
192
|
+
return BUILD_PIXEL( bytes[start + 1 + (x * 8) + 0],
|
193
|
+
bytes[start + 1 + (x * 8) + 2],
|
194
|
+
bytes[start + 1 + (x * 8) + 4],
|
195
|
+
bytes[start + 1 + (x * 8) + 6]);
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
pixel_decoder_func oily_png_decode_pixel_func(int color_mode, int bit_depth) {
|
200
|
+
switch (color_mode) {
|
201
|
+
case OILY_PNG_COLOR_GRAYSCALE:
|
202
|
+
switch (bit_depth) {
|
203
|
+
case 1: return &oily_png_decode_pixel_grayscale_1bit;
|
204
|
+
case 2: return &oily_png_decode_pixel_grayscale_2bit;
|
205
|
+
case 4: return &oily_png_decode_pixel_grayscale_4bit;
|
206
|
+
case 8: return &oily_png_decode_pixel_grayscale_8bit;
|
207
|
+
case 16: return &oily_png_decode_pixel_grayscale_16bit;
|
208
|
+
default: return NULL;
|
209
|
+
}
|
210
|
+
|
211
|
+
case OILY_PNG_COLOR_TRUECOLOR:
|
212
|
+
switch (bit_depth) {
|
213
|
+
case 8: return &oily_png_decode_pixel_truecolor_8bit;
|
214
|
+
case 16: return &oily_png_decode_pixel_truecolor_16bit;
|
215
|
+
default: return NULL;
|
216
|
+
}
|
217
|
+
|
218
|
+
case OILY_PNG_COLOR_INDEXED:
|
219
|
+
switch (bit_depth) {
|
220
|
+
case 1: return &oily_png_decode_pixel_indexed_1bit;
|
221
|
+
case 2: return &oily_png_decode_pixel_indexed_2bit;
|
222
|
+
case 4: return &oily_png_decode_pixel_indexed_4bit;
|
223
|
+
case 8: return &oily_png_decode_pixel_indexed_8bit;
|
224
|
+
default: return NULL;
|
225
|
+
}
|
226
|
+
|
227
|
+
case OILY_PNG_COLOR_GRAYSCALE_ALPHA:
|
228
|
+
switch (bit_depth) {
|
229
|
+
case 8: return &oily_png_decode_pixel_grayscale_alpha_8bit;
|
230
|
+
case 16: return &oily_png_decode_pixel_grayscale_alpha_16bit;
|
231
|
+
default: return NULL;
|
232
|
+
}
|
233
|
+
|
234
|
+
case OILY_PNG_COLOR_TRUECOLOR_ALPHA:
|
235
|
+
switch (bit_depth) {
|
236
|
+
case 8: return &oily_png_decode_pixel_truecolor_alpha_8bit;
|
237
|
+
case 16: return &oily_png_decode_pixel_truecolor_alpha_16bit;
|
238
|
+
default: return NULL;
|
239
|
+
}
|
240
|
+
|
241
|
+
default: return NULL;
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE depth, VALUE start_pos) {
|
76
246
|
|
77
247
|
VALUE pixels = rb_ary_new();
|
78
248
|
|
79
|
-
|
80
|
-
if (RSTRING_LEN(stream) < pass_size + FIX2INT(start_pos)) {
|
81
|
-
rb_raise(rb_eRuntimeError, "The length of the stream is too short to contain the image!");
|
82
|
-
}
|
249
|
+
if ((FIX2LONG(height) > 0) && (FIX2LONG(width) > 0)) {
|
83
250
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
251
|
+
char pixel_size = oily_png_pixel_bytesize(FIX2INT(color_mode), FIX2INT(depth));
|
252
|
+
long line_size = oily_png_scanline_bytesize(FIX2INT(color_mode), FIX2INT(depth), FIX2LONG(width));
|
253
|
+
long pass_size = oily_png_pass_bytesize(FIX2INT(color_mode), FIX2INT(depth), FIX2LONG(width), FIX2LONG(height));
|
254
|
+
|
255
|
+
// Make sure that the stream is large enough to contain our pass.
|
256
|
+
if (RSTRING_LEN(stream) < pass_size + FIX2LONG(start_pos)) {
|
257
|
+
rb_raise(rb_eRuntimeError, "The length of the stream is too short to contain the image!");
|
258
|
+
}
|
89
259
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
}
|
260
|
+
// Copy the bytes for this pass from the stream to a separate location
|
261
|
+
// so we can work on this byte array directly.
|
262
|
+
BYTE* bytes = ALLOCA_N(BYTE, pass_size);
|
263
|
+
memcpy(bytes, RSTRING_PTR(stream) + FIX2LONG(start_pos), pass_size);
|
95
264
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
}
|
265
|
+
// Get the decoding palette for indexed images.
|
266
|
+
VALUE decoding_palette = Qnil;
|
267
|
+
if (FIX2INT(color_mode) == OILY_PNG_COLOR_INDEXED) {
|
268
|
+
decoding_palette = rb_funcall(self, rb_intern("decoding_palette"), 0);
|
269
|
+
}
|
270
|
+
|
271
|
+
// Select the pixel decoder function for this color mode.
|
272
|
+
PIXEL (*pixel_decoder)(BYTE*, long, long, VALUE) = NULL;
|
273
|
+
pixel_decoder = oily_png_decode_pixel_func(FIX2INT(color_mode), FIX2INT(depth));
|
106
274
|
|
107
|
-
|
108
|
-
|
275
|
+
if (pixel_decoder == NULL) {
|
276
|
+
rb_raise(rb_eRuntimeError, "No decoder for color mode %d and bit depth %d", FIX2INT(color_mode), FIX2INT(depth));
|
277
|
+
}
|
278
|
+
|
279
|
+
long y, x, line_start;
|
280
|
+
PIXEL pixel;
|
109
281
|
|
110
|
-
|
111
|
-
|
282
|
+
for (y = 0; y < FIX2LONG(height); y++) {
|
283
|
+
line_start = y * line_size;
|
112
284
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
285
|
+
// Apply filering to the line
|
286
|
+
switch (bytes[line_start]) {
|
287
|
+
case OILY_PNG_FILTER_NONE: break;
|
288
|
+
case OILY_PNG_FILTER_SUB: oily_png_decode_filter_sub( bytes, line_start, line_size, pixel_size); break;
|
289
|
+
case OILY_PNG_FILTER_UP: oily_png_decode_filter_up( bytes, line_start, line_size, pixel_size); break;
|
290
|
+
case OILY_PNG_FILTER_AVERAGE: oily_png_decode_filter_average( bytes, line_start, line_size, pixel_size); break;
|
291
|
+
case OILY_PNG_FILTER_PAETH: oily_png_decode_filter_paeth( bytes, line_start, line_size, pixel_size); break;
|
292
|
+
default: rb_raise(rb_eRuntimeError, "Filter type not supported: %d", bytes[line_start]);
|
293
|
+
}
|
122
294
|
|
123
|
-
|
124
|
-
|
295
|
+
// Set the filter byte to 0 because the bytearray is now unfiltered.
|
296
|
+
bytes[line_start] = OILY_PNG_FILTER_NONE;
|
125
297
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
rb_ary_store(pixels, pixel_index, INT2NUM(pixel));
|
298
|
+
// Now, iterate over all bytes in this line and convert them into pixels
|
299
|
+
for (x = 0; x < FIX2LONG(width); x++) {
|
300
|
+
pixel = pixel_decoder(bytes, line_start, x, decoding_palette);
|
301
|
+
rb_ary_store(pixels, FIX2LONG(width) * y + x, UINT2NUM(pixel));
|
302
|
+
}
|
132
303
|
}
|
133
304
|
}
|
134
305
|
|
data/ext/oily_png/png_decoding.h
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
#define BUILD_PIXEL(r, g, b, a) (((PIXEL) r << 24) + ((PIXEL) g << 16) + ((PIXEL) b << 8) + (PIXEL) a)
|
5
5
|
#define UNFILTER_BYTE(byte, adjustment) byte = (BYTE) (((byte) + (adjustment)) & 0x000000ff)
|
6
6
|
|
7
|
+
typedef PIXEL(*pixel_decoder_func)(BYTE*, long, long, VALUE);
|
8
|
+
|
9
|
+
|
7
10
|
/*
|
8
11
|
Decodes an image pass from the given byte stream at the given position.
|
9
12
|
A normal PNG will only have one pass that consumes the entire stream, while an
|
@@ -11,6 +14,6 @@
|
|
11
14
|
|
12
15
|
This function shouild replace ChunkyPNG::Canvas::PNGDecoding.decode_png_image_pass
|
13
16
|
*/
|
14
|
-
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE start_pos);
|
17
|
+
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE depth, VALUE start_pos);
|
15
18
|
|
16
19
|
#endif
|
data/ext/oily_png/png_encoding.c
CHANGED
@@ -2,47 +2,47 @@
|
|
2
2
|
|
3
3
|
///// Pixel encoding functions //////////////////////////////////////////
|
4
4
|
|
5
|
-
void oily_png_encode_pixel_grayscale(PIXEL pixel, BYTE* bytes,
|
5
|
+
void oily_png_encode_pixel_grayscale(PIXEL pixel, BYTE* bytes, long pos, VALUE palette) {
|
6
6
|
// Assume R == G == B. ChunkyPNG uses the B byte fot performance reasons.
|
7
7
|
// We'll uses the same to reomain compatible with ChunkyPNG.
|
8
8
|
bytes[pos] = B_BYTE(pixel);
|
9
9
|
}
|
10
10
|
|
11
|
-
void oily_png_encode_pixel_grayscale_alpha(PIXEL pixel, BYTE* bytes,
|
11
|
+
void oily_png_encode_pixel_grayscale_alpha(PIXEL pixel, BYTE* bytes, long pos, VALUE palette) {
|
12
12
|
// Assume R == G == B. ChunkyPNG uses the B byte fot performance reasons.
|
13
13
|
// We'll uses the same to reomain compatible with ChunkyPNG.
|
14
14
|
bytes[pos + 0] = B_BYTE(pixel);
|
15
15
|
bytes[pos + 1] = A_BYTE(pixel);
|
16
16
|
}
|
17
17
|
|
18
|
-
void oily_png_encode_pixel_truecolor(PIXEL pixel, BYTE* bytes,
|
18
|
+
void oily_png_encode_pixel_truecolor(PIXEL pixel, BYTE* bytes, long pos, VALUE palette) {
|
19
19
|
bytes[pos + 0] = R_BYTE(pixel);
|
20
20
|
bytes[pos + 1] = G_BYTE(pixel);
|
21
21
|
bytes[pos + 2] = B_BYTE(pixel);
|
22
22
|
}
|
23
23
|
|
24
|
-
void oily_png_encode_pixel_truecolor_alpha(PIXEL pixel, BYTE* bytes,
|
24
|
+
void oily_png_encode_pixel_truecolor_alpha(PIXEL pixel, BYTE* bytes, long pos, VALUE palette) {
|
25
25
|
bytes[pos + 0] = R_BYTE(pixel);
|
26
26
|
bytes[pos + 1] = G_BYTE(pixel);
|
27
27
|
bytes[pos + 2] = B_BYTE(pixel);
|
28
28
|
bytes[pos + 3] = A_BYTE(pixel);
|
29
29
|
}
|
30
30
|
|
31
|
-
void oily_png_encode_pixel_indexed(PIXEL pixel, BYTE* bytes,
|
31
|
+
void oily_png_encode_pixel_indexed(PIXEL pixel, BYTE* bytes, long pos, VALUE palette) {
|
32
32
|
bytes[pos] = (BYTE) NUM2UINT(rb_funcall(palette, rb_intern("index"), 1, UINT2NUM(pixel)));
|
33
33
|
}
|
34
34
|
|
35
35
|
///// Scanline filtering functions //////////////////////////////////////////
|
36
36
|
|
37
|
-
void oily_png_encode_filter_sub(BYTE* bytes,
|
38
|
-
|
37
|
+
void oily_png_encode_filter_sub(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
38
|
+
long x;
|
39
39
|
for (x = line_size - 1; x > pixel_size; x--) {
|
40
40
|
FILTER_BYTE(bytes[pos + x], bytes[pos + x - pixel_size]);
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
44
|
-
void oily_png_encode_filter_up(BYTE* bytes,
|
45
|
-
|
44
|
+
void oily_png_encode_filter_up(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
45
|
+
long x;
|
46
46
|
if (pos >= line_size) {
|
47
47
|
for (x = line_size - 1; x > 0; x--) {
|
48
48
|
FILTER_BYTE(bytes[pos + x], bytes[pos + x - line_size]);
|
@@ -50,8 +50,8 @@ void oily_png_encode_filter_up(BYTE* bytes, int pos, int line_size, int pixel_si
|
|
50
50
|
}
|
51
51
|
}
|
52
52
|
|
53
|
-
void oily_png_encode_filter_average(BYTE* bytes,
|
54
|
-
|
53
|
+
void oily_png_encode_filter_average(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
54
|
+
long x; BYTE a, b;
|
55
55
|
for (x = line_size - 1; x > 0; x--) {
|
56
56
|
a = (x > pixel_size) ? bytes[pos + x - pixel_size] : 0;
|
57
57
|
b = (pos >= line_size) ? bytes[pos + x - line_size] : 0;
|
@@ -59,8 +59,8 @@ void oily_png_encode_filter_average(BYTE* bytes, int pos, int line_size, int pix
|
|
59
59
|
}
|
60
60
|
}
|
61
61
|
|
62
|
-
void oily_png_encode_filter_paeth(BYTE* bytes,
|
63
|
-
|
62
|
+
void oily_png_encode_filter_paeth(BYTE* bytes, long pos, long line_size, char pixel_size) {
|
63
|
+
long x; int p, pa, pb, pc; BYTE a, b, c, pr;
|
64
64
|
for (x = line_size - 1; x > 0; x--) {
|
65
65
|
a = (x > pixel_size) ? bytes[pos + x - pixel_size] : 0;
|
66
66
|
b = (pos >= line_size) ? bytes[pos + x - line_size] : 0;
|
@@ -77,8 +77,9 @@ void oily_png_encode_filter_paeth(BYTE* bytes, int pos, int line_size, int pixel
|
|
77
77
|
VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE color_mode, VALUE filtering) {
|
78
78
|
|
79
79
|
// Get the data
|
80
|
-
|
81
|
-
|
80
|
+
char depth = 8;
|
81
|
+
long width = FIX2LONG(rb_funcall(self, rb_intern("width"), 0));
|
82
|
+
long height = FIX2LONG(rb_funcall(self, rb_intern("height"), 0));
|
82
83
|
VALUE pixels = rb_funcall(self, rb_intern("pixels"), 0);
|
83
84
|
|
84
85
|
if (RARRAY_LEN(pixels) != width * height) {
|
@@ -91,27 +92,27 @@ VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE c
|
|
91
92
|
palette = rb_funcall(self, rb_intern("encoding_palette"), 0);
|
92
93
|
}
|
93
94
|
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
char pixel_size = oily_png_pixel_bytesize(FIX2INT(color_mode), depth);
|
96
|
+
long line_size = oily_png_scanline_bytesize(FIX2INT(color_mode), depth, width);
|
97
|
+
long pass_size = oily_png_pass_bytesize(FIX2INT(color_mode), depth, width, height);
|
97
98
|
|
98
99
|
// Allocate memory for the byte array.
|
99
100
|
BYTE* bytes = ALLOCA_N(BYTE, pass_size);
|
100
101
|
|
101
102
|
// Select out pixel encoder function based on the color mode.
|
102
|
-
void (*pixel_encoder)(PIXEL, BYTE*,
|
103
|
+
void (*pixel_encoder)(PIXEL, BYTE*, long, VALUE) = NULL;
|
103
104
|
switch (FIX2INT(color_mode)) {
|
104
105
|
case OILY_PNG_COLOR_GRAYSCALE: pixel_encoder = &oily_png_encode_pixel_grayscale; break;
|
105
106
|
case OILY_PNG_COLOR_TRUECOLOR: pixel_encoder = &oily_png_encode_pixel_truecolor; break;
|
106
107
|
case OILY_PNG_COLOR_INDEXED: pixel_encoder = &oily_png_encode_pixel_indexed; break;
|
107
108
|
case OILY_PNG_COLOR_GRAYSCALE_ALPHA: pixel_encoder = &oily_png_encode_pixel_grayscale_alpha; break;
|
108
109
|
case OILY_PNG_COLOR_TRUECOLOR_ALPHA: pixel_encoder = &oily_png_encode_pixel_truecolor_alpha; break;
|
109
|
-
default: rb_raise(rb_eRuntimeError, "Unsupported color mode: %
|
110
|
+
default: rb_raise(rb_eRuntimeError, "Unsupported color mode: %d", FIX2INT(color_mode));
|
110
111
|
}
|
111
112
|
|
112
113
|
// Loop over all the pixels to encode them into the byte array.
|
113
114
|
PIXEL pixel;
|
114
|
-
|
115
|
+
long x, y, pos;
|
115
116
|
for (y = 0; y < height; y++) {
|
116
117
|
bytes[line_size * y] = (BYTE) FIX2INT(filtering);
|
117
118
|
|
@@ -126,13 +127,13 @@ VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE c
|
|
126
127
|
if (FIX2INT(filtering) != OILY_PNG_FILTER_NONE) {
|
127
128
|
|
128
129
|
// Assign the chosen filter function to the scanline_filter variable.
|
129
|
-
void (*scanline_filter)(BYTE*,
|
130
|
+
void (*scanline_filter)(BYTE*, long, long, char) = NULL;
|
130
131
|
switch (FIX2INT(filtering)) {
|
131
132
|
case OILY_PNG_FILTER_SUB: scanline_filter = &oily_png_encode_filter_sub; break;
|
132
133
|
case OILY_PNG_FILTER_UP: scanline_filter = &oily_png_encode_filter_up; break;
|
133
134
|
case OILY_PNG_FILTER_AVERAGE: scanline_filter = &oily_png_encode_filter_average; break;
|
134
135
|
case OILY_PNG_FILTER_PAETH: scanline_filter = &oily_png_encode_filter_paeth; break;
|
135
|
-
default: rb_raise(rb_eRuntimeError, "Unsupported filter type: %
|
136
|
+
default: rb_raise(rb_eRuntimeError, "Unsupported filter type: %d", FIX2INT(filtering));
|
136
137
|
}
|
137
138
|
|
138
139
|
// Now, apply the scanline_filter function to every line, backwards.
|
data/lib/oily_png.rb
CHANGED
data/oily_png.gemspec
CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|
4
4
|
|
5
5
|
# Do not change the version and date fields by hand. This will be done
|
6
6
|
# automatically by the gem release script.
|
7
|
-
s.version = "0.
|
8
|
-
s.date = "2010-
|
7
|
+
s.version = "0.2.0"
|
8
|
+
s.date = "2010-11-01"
|
9
9
|
|
10
10
|
s.summary = "Native mixin to speed up ChunkyPNG"
|
11
11
|
s.description = <<-EOT
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.extensions = ["ext/oily_png/extconf.rb"]
|
20
20
|
s.require_paths = ["lib", "ext"]
|
21
21
|
|
22
|
-
s.add_runtime_dependency('chunky_png', '~> 0.
|
22
|
+
s.add_runtime_dependency('chunky_png', '~> 0.11')
|
23
23
|
|
24
24
|
s.add_development_dependency('rake')
|
25
25
|
s.add_development_dependency('rspec', '~> 2.0')
|
@@ -29,6 +29,6 @@ Gem::Specification.new do |s|
|
|
29
29
|
|
30
30
|
# Do not change the files and test_files fields by hand. This will be done
|
31
31
|
# automatically by the gem release script.
|
32
|
-
s.files = %w(.gitignore Gemfile Gemfile.lock LICENSE README.rdoc Rakefile ext/oily_png/extconf.rb ext/oily_png/oily_png_ext.c ext/oily_png/oily_png_ext.h ext/oily_png/png_decoding.c ext/oily_png/png_decoding.h ext/oily_png/png_encoding.c ext/oily_png/png_encoding.h lib/oily_png.rb oily_png.gemspec spec/decoding_spec.rb spec/encoding_spec.rb spec/resources/gray.png spec/resources/interlaced.png spec/resources/nonsquare.png spec/resources/square.png spec/spec_helper.rb tasks/github-gem.rake tasks/testing.rake)
|
32
|
+
s.files = %w(.gitignore Gemfile Gemfile.lock LICENSE README.rdoc Rakefile ext/oily_png/extconf.rb ext/oily_png/oily_png_ext.c ext/oily_png/oily_png_ext.h ext/oily_png/png_decoding.c ext/oily_png/png_decoding.h ext/oily_png/png_encoding.c ext/oily_png/png_encoding.h lib/oily_png.rb oily_png.gemspec spec/decoding_spec.rb spec/encoding_spec.rb spec/resources/basi0g01.png spec/resources/basi0g02.png spec/resources/basi0g04.png spec/resources/basi0g08.png spec/resources/basi0g16.png spec/resources/basi2c08.png spec/resources/basi2c16.png spec/resources/basi3p01.png spec/resources/basi3p02.png spec/resources/basi3p04.png spec/resources/basi3p08.png spec/resources/basi4a08.png spec/resources/basi4a16.png spec/resources/basi6a08.png spec/resources/basi6a16.png spec/resources/basn0g01.png spec/resources/basn0g02.png spec/resources/basn0g04.png spec/resources/basn0g08.png spec/resources/basn0g16.png spec/resources/basn2c08.png spec/resources/basn2c16.png spec/resources/basn3p01.png spec/resources/basn3p02.png spec/resources/basn3p04.png spec/resources/basn3p08.png spec/resources/basn4a08.png spec/resources/basn4a16.png spec/resources/basn6a08.png spec/resources/basn6a16.png spec/resources/gray.png spec/resources/interlaced.png spec/resources/nonsquare.png spec/resources/s01i3p01.png spec/resources/s01n3p01.png spec/resources/s02i3p01.png spec/resources/s02n3p01.png spec/resources/s03i3p01.png spec/resources/s03n3p01.png spec/resources/s04i3p01.png spec/resources/s04n3p01.png spec/resources/s05i3p02.png spec/resources/s05n3p02.png spec/resources/s06i3p02.png spec/resources/s06n3p02.png spec/resources/s07i3p02.png spec/resources/s07n3p02.png spec/resources/s08i3p02.png spec/resources/s08n3p02.png spec/resources/s09i3p02.png spec/resources/s09n3p02.png spec/resources/s32i3p04.png spec/resources/s32n3p04.png spec/resources/s33i3p04.png spec/resources/s33n3p04.png spec/resources/s34i3p04.png spec/resources/s34n3p04.png spec/resources/s35i3p04.png spec/resources/s35n3p04.png spec/resources/s36i3p04.png spec/resources/s36n3p04.png spec/resources/s37i3p04.png spec/resources/s37n3p04.png spec/resources/s38i3p04.png spec/resources/s38n3p04.png spec/resources/s39i3p04.png spec/resources/s39n3p04.png spec/resources/s40i3p04.png spec/resources/s40n3p04.png spec/resources/square.png spec/spec_helper.rb tasks/github-gem.rake tasks/testing.rake)
|
33
33
|
s.test_files = %w(spec/decoding_spec.rb spec/encoding_spec.rb)
|
34
34
|
end
|
data/spec/decoding_spec.rb
CHANGED
@@ -2,20 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe OilyPNG::PNGDecoding do
|
4
4
|
|
5
|
-
it "should call Color.
|
6
|
-
ChunkyPNG::Color.should_receive(:
|
5
|
+
it "should call ChunkyPNG::Color.pixel_bytesize in the pure ruby version" do
|
6
|
+
ChunkyPNG::Color.should_receive(:pixel_bytesize).and_return(3)
|
7
7
|
ChunkyPNG::Canvas.from_file(resource_file('square.png'))
|
8
8
|
end
|
9
9
|
|
10
|
-
it "should not call Color.
|
11
|
-
ChunkyPNG::Color.should_not_receive(:
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should decode an interlaced image correctly" do
|
16
|
-
c1 = OilyCanvas.from_file(resource_file('interlaced.png'))
|
17
|
-
c2 = ChunkyPNG::Canvas.from_file(resource_file('interlaced.png'))
|
18
|
-
c2.should == c1
|
10
|
+
it "should not call ChunkyPNG::Color.pixel_bytesize in the native version" do
|
11
|
+
ChunkyPNG::Color.should_not_receive(:pixel_bytesize)
|
12
|
+
OilyPNG::Canvas.from_file(resource_file('square.png'))
|
19
13
|
end
|
20
14
|
|
21
15
|
context 'decoding different filtering methods' do
|
@@ -23,56 +17,35 @@ describe OilyPNG::PNGDecoding do
|
|
23
17
|
|
24
18
|
it "should decode NONE filtering exactly the same as ChunkyPNG" do
|
25
19
|
filtered_data = @reference.to_blob(:filtering => ChunkyPNG::FILTER_NONE)
|
26
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should ==
|
20
|
+
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyPNG::Canvas.from_blob(filtered_data)
|
27
21
|
end
|
28
22
|
|
29
23
|
it "should decode SUB filtering exactly the same as ChunkyPNG" do
|
30
24
|
filtered_data = @reference.to_blob(:filtering => ChunkyPNG::FILTER_SUB)
|
31
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should ==
|
25
|
+
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyPNG::Canvas.from_blob(filtered_data)
|
32
26
|
end
|
33
27
|
|
34
28
|
it "should decode UP filtering exactly the same as ChunkyPNG" do
|
35
29
|
filtered_data = @reference.to_blob(:filtering => ChunkyPNG::FILTER_UP)
|
36
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should ==
|
30
|
+
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyPNG::Canvas.from_blob(filtered_data)
|
37
31
|
end
|
38
32
|
|
39
33
|
it "should decode AVERAGE filtering exactly the same as ChunkyPNG" do
|
40
34
|
filtered_data = @reference.to_blob(:filtering => ChunkyPNG::FILTER_AVERAGE)
|
41
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should ==
|
35
|
+
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyPNG::Canvas.from_blob(filtered_data)
|
42
36
|
end
|
43
37
|
|
44
38
|
it "should decode PAETH filtering exactly the same as ChunkyPNG" do
|
45
39
|
filtered_data = @reference.to_blob(:filtering => ChunkyPNG::FILTER_PAETH)
|
46
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should ==
|
40
|
+
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyPNG::Canvas.from_blob(filtered_data)
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
50
|
-
context 'decoding
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyCanvas.from_blob(filtered_data)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should decode RGB images exactly the same as ChunkyPNG" do
|
59
|
-
filtered_data = @reference.to_blob(:color_mode => ChunkyPNG::COLOR_TRUECOLOR)
|
60
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyCanvas.from_blob(filtered_data)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should decode indexed images exactly the same as ChunkyPNG" do
|
64
|
-
filtered_data = @reference.to_blob(:color_mode => ChunkyPNG::COLOR_INDEXED)
|
65
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyCanvas.from_blob(filtered_data)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should decode grayscale images exactly the same as ChunkyPNG" do
|
69
|
-
filtered_data = @reference.to_blob(:color_mode => ChunkyPNG::COLOR_GRAYSCALE)
|
70
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyCanvas.from_blob(filtered_data)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should decode grayscale images with transparency the same as ChunkyPNG" do
|
74
|
-
filtered_data = @reference.to_blob(:color_mode => ChunkyPNG::COLOR_GRAYSCALE_ALPHA)
|
75
|
-
ChunkyPNG::Canvas.from_blob(filtered_data).should == OilyCanvas.from_blob(filtered_data)
|
44
|
+
context 'decoding compatibility with ChunkyPNG' do
|
45
|
+
resource_files.each do |file|
|
46
|
+
it "should #{File.basename(file)} the same as ChunkyPNG" do
|
47
|
+
OilyPNG::Canvas.from_file(file).pixels.should == ChunkyPNG::Canvas.from_file(file).pixels
|
48
|
+
end
|
76
49
|
end
|
77
50
|
end
|
78
51
|
end
|
data/spec/encoding_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe OilyPNG::PNGEncoding do
|
|
5
5
|
context 'encoding different color modes' do
|
6
6
|
before do
|
7
7
|
@canvas = ChunkyPNG::Canvas.from_file(resource_file('gray.png'))
|
8
|
-
@oily_canvas =
|
8
|
+
@oily_canvas = OilyPNG::Canvas.from_canvas(@canvas)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should encode an image using grayscale correctly" do
|
@@ -47,7 +47,7 @@ describe OilyPNG::PNGEncoding do
|
|
47
47
|
context 'encoding different filters' do
|
48
48
|
before do
|
49
49
|
@canvas = ChunkyPNG::Canvas.from_file(resource_file('nonsquare.png'))
|
50
|
-
@oily_canvas =
|
50
|
+
@oily_canvas = OilyPNG::Canvas.from_canvas(@canvas)
|
51
51
|
end
|
52
52
|
|
53
53
|
it "should encode correctly with no filtering" do
|
@@ -83,7 +83,7 @@ describe OilyPNG::PNGEncoding do
|
|
83
83
|
|
84
84
|
it "should encode an interlaced image correctly" do
|
85
85
|
canvas = ChunkyPNG::Canvas.from_file(resource_file('interlaced.png'))
|
86
|
-
data =
|
86
|
+
data = OilyPNG::Canvas.from_canvas(canvas).to_blob(:interlace => true)
|
87
87
|
ds = ChunkyPNG::Datastream.from_blob(data)
|
88
88
|
ds.header_chunk.interlace.should == ChunkyPNG::INTERLACING_ADAM7
|
89
89
|
ChunkyPNG::Canvas.from_datastream(ds).should == canvas
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
@@ -7,9 +7,12 @@ require 'rspec'
|
|
7
7
|
require 'chunky_png'
|
8
8
|
require 'oily_png/oily_png_ext'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
|
11
|
+
module OilyPNG
|
12
|
+
class Canvas < ChunkyPNG::Canvas
|
13
|
+
extend OilyPNG::PNGDecoding
|
14
|
+
include OilyPNG::PNGEncoding
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
module ResourceHelper
|
@@ -20,6 +23,10 @@ end
|
|
20
23
|
|
21
24
|
module CanvasHelper
|
22
25
|
|
26
|
+
def resource_files(pattern = "*.png")
|
27
|
+
Dir[File.join(File.dirname(__FILE__), 'resources', pattern)]
|
28
|
+
end
|
29
|
+
|
23
30
|
def resource_file(name)
|
24
31
|
File.join(File.dirname(__FILE__), 'resources', name)
|
25
32
|
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oily_png
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 25
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Willem van Bergen
|
@@ -15,54 +14,50 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-
|
17
|
+
date: 2010-11-01 00:00:00 +01:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
21
|
+
name: chunky_png
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
23
|
none: false
|
24
24
|
requirements:
|
25
25
|
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
hash: 63
|
28
27
|
segments:
|
29
28
|
- 0
|
30
|
-
-
|
31
|
-
|
32
|
-
version: 0.10.4
|
33
|
-
requirement: *id001
|
29
|
+
- 11
|
30
|
+
version: "0.11"
|
34
31
|
type: :runtime
|
35
|
-
name: chunky_png
|
36
32
|
prerelease: false
|
33
|
+
version_requirements: *id001
|
37
34
|
- !ruby/object:Gem::Dependency
|
38
|
-
|
35
|
+
name: rake
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
37
|
none: false
|
40
38
|
requirements:
|
41
39
|
- - ">="
|
42
40
|
- !ruby/object:Gem::Version
|
43
|
-
hash: 3
|
44
41
|
segments:
|
45
42
|
- 0
|
46
43
|
version: "0"
|
47
|
-
requirement: *id002
|
48
44
|
type: :development
|
49
|
-
name: rake
|
50
45
|
prerelease: false
|
46
|
+
version_requirements: *id002
|
51
47
|
- !ruby/object:Gem::Dependency
|
52
|
-
|
48
|
+
name: rspec
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
50
|
none: false
|
54
51
|
requirements:
|
55
52
|
- - ~>
|
56
53
|
- !ruby/object:Gem::Version
|
57
|
-
hash: 3
|
58
54
|
segments:
|
59
55
|
- 2
|
60
56
|
- 0
|
61
57
|
version: "2.0"
|
62
|
-
requirement: *id003
|
63
58
|
type: :development
|
64
|
-
name: rspec
|
65
59
|
prerelease: false
|
60
|
+
version_requirements: *id003
|
66
61
|
description: " This Ruby C extenstion defines a module that can be included into ChunkyPNG to improve its speed.\n"
|
67
62
|
email:
|
68
63
|
- willem@railsdoctors.com
|
@@ -90,9 +85,75 @@ files:
|
|
90
85
|
- oily_png.gemspec
|
91
86
|
- spec/decoding_spec.rb
|
92
87
|
- spec/encoding_spec.rb
|
88
|
+
- spec/resources/basi0g01.png
|
89
|
+
- spec/resources/basi0g02.png
|
90
|
+
- spec/resources/basi0g04.png
|
91
|
+
- spec/resources/basi0g08.png
|
92
|
+
- spec/resources/basi0g16.png
|
93
|
+
- spec/resources/basi2c08.png
|
94
|
+
- spec/resources/basi2c16.png
|
95
|
+
- spec/resources/basi3p01.png
|
96
|
+
- spec/resources/basi3p02.png
|
97
|
+
- spec/resources/basi3p04.png
|
98
|
+
- spec/resources/basi3p08.png
|
99
|
+
- spec/resources/basi4a08.png
|
100
|
+
- spec/resources/basi4a16.png
|
101
|
+
- spec/resources/basi6a08.png
|
102
|
+
- spec/resources/basi6a16.png
|
103
|
+
- spec/resources/basn0g01.png
|
104
|
+
- spec/resources/basn0g02.png
|
105
|
+
- spec/resources/basn0g04.png
|
106
|
+
- spec/resources/basn0g08.png
|
107
|
+
- spec/resources/basn0g16.png
|
108
|
+
- spec/resources/basn2c08.png
|
109
|
+
- spec/resources/basn2c16.png
|
110
|
+
- spec/resources/basn3p01.png
|
111
|
+
- spec/resources/basn3p02.png
|
112
|
+
- spec/resources/basn3p04.png
|
113
|
+
- spec/resources/basn3p08.png
|
114
|
+
- spec/resources/basn4a08.png
|
115
|
+
- spec/resources/basn4a16.png
|
116
|
+
- spec/resources/basn6a08.png
|
117
|
+
- spec/resources/basn6a16.png
|
93
118
|
- spec/resources/gray.png
|
94
119
|
- spec/resources/interlaced.png
|
95
120
|
- spec/resources/nonsquare.png
|
121
|
+
- spec/resources/s01i3p01.png
|
122
|
+
- spec/resources/s01n3p01.png
|
123
|
+
- spec/resources/s02i3p01.png
|
124
|
+
- spec/resources/s02n3p01.png
|
125
|
+
- spec/resources/s03i3p01.png
|
126
|
+
- spec/resources/s03n3p01.png
|
127
|
+
- spec/resources/s04i3p01.png
|
128
|
+
- spec/resources/s04n3p01.png
|
129
|
+
- spec/resources/s05i3p02.png
|
130
|
+
- spec/resources/s05n3p02.png
|
131
|
+
- spec/resources/s06i3p02.png
|
132
|
+
- spec/resources/s06n3p02.png
|
133
|
+
- spec/resources/s07i3p02.png
|
134
|
+
- spec/resources/s07n3p02.png
|
135
|
+
- spec/resources/s08i3p02.png
|
136
|
+
- spec/resources/s08n3p02.png
|
137
|
+
- spec/resources/s09i3p02.png
|
138
|
+
- spec/resources/s09n3p02.png
|
139
|
+
- spec/resources/s32i3p04.png
|
140
|
+
- spec/resources/s32n3p04.png
|
141
|
+
- spec/resources/s33i3p04.png
|
142
|
+
- spec/resources/s33n3p04.png
|
143
|
+
- spec/resources/s34i3p04.png
|
144
|
+
- spec/resources/s34n3p04.png
|
145
|
+
- spec/resources/s35i3p04.png
|
146
|
+
- spec/resources/s35n3p04.png
|
147
|
+
- spec/resources/s36i3p04.png
|
148
|
+
- spec/resources/s36n3p04.png
|
149
|
+
- spec/resources/s37i3p04.png
|
150
|
+
- spec/resources/s37n3p04.png
|
151
|
+
- spec/resources/s38i3p04.png
|
152
|
+
- spec/resources/s38n3p04.png
|
153
|
+
- spec/resources/s39i3p04.png
|
154
|
+
- spec/resources/s39n3p04.png
|
155
|
+
- spec/resources/s40i3p04.png
|
156
|
+
- spec/resources/s40n3p04.png
|
96
157
|
- spec/resources/square.png
|
97
158
|
- spec/spec_helper.rb
|
98
159
|
- tasks/github-gem.rake
|
@@ -117,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
178
|
requirements:
|
118
179
|
- - ">="
|
119
180
|
- !ruby/object:Gem::Version
|
120
|
-
hash:
|
181
|
+
hash: -58392216600872723
|
121
182
|
segments:
|
122
183
|
- 0
|
123
184
|
version: "0"
|
@@ -126,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
187
|
requirements:
|
127
188
|
- - ">="
|
128
189
|
- !ruby/object:Gem::Version
|
129
|
-
hash:
|
190
|
+
hash: -58392216600872723
|
130
191
|
segments:
|
131
192
|
- 0
|
132
193
|
version: "0"
|