oily_png 0.0.3 → 0.0.4
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/Gemfile.lock +4 -4
- data/README.rdoc +2 -1
- data/ext/oily_png/extconf.rb +1 -1
- data/ext/oily_png/oily_png_ext.c +26 -0
- data/ext/oily_png/oily_png_ext.h +30 -0
- data/ext/oily_png/png_decoding.c +29 -64
- data/ext/oily_png/png_decoding.h +7 -0
- data/ext/oily_png/png_encoding.c +130 -0
- data/ext/oily_png/png_encoding.h +7 -0
- data/lib/oily_png.rb +5 -2
- data/oily_png.gemspec +4 -4
- data/spec/encoding_spec.rb +83 -0
- data/spec/spec_helper.rb +2 -1
- metadata +13 -6
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
oily_png (0.0.
|
5
|
-
chunky_png (~> 0.10.
|
4
|
+
oily_png (0.0.4)
|
5
|
+
chunky_png (~> 0.10.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
-
chunky_png (0.10.
|
10
|
+
chunky_png (0.10.2)
|
11
11
|
rake (0.8.7)
|
12
12
|
rspec (1.3.0)
|
13
13
|
|
@@ -15,7 +15,7 @@ PLATFORMS
|
|
15
15
|
ruby
|
16
16
|
|
17
17
|
DEPENDENCIES
|
18
|
-
chunky_png (~> 0.10.
|
18
|
+
chunky_png (~> 0.10.2)
|
19
19
|
oily_png!
|
20
20
|
rake
|
21
21
|
rspec (>= 1.3)
|
data/README.rdoc
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
= OilyPNG
|
2
2
|
|
3
|
-
OilyPNG is a Ruby C extension to speed up the pure Ruby ChunkyPNG library.
|
3
|
+
OilyPNG is a Ruby C extension to speed up the pure Ruby ChunkyPNG library. It is a standalone
|
4
|
+
module, so it does not require LibPNG, ImageMagick or any other library.
|
4
5
|
|
5
6
|
Currently it has an alternative implementation of decoding PNGs, making that operation much
|
6
7
|
faster for PNG images that apply filtering. An alternative implementation for encoding is
|
data/ext/oily_png/extconf.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
create_makefile('oily_png/
|
2
|
+
create_makefile('oily_png/oily_png_ext')
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#include "oily_png_ext.h"
|
2
|
+
|
3
|
+
// Initialize the extension by creating the OilyPNG modules.
|
4
|
+
void Init_oily_png_ext() {
|
5
|
+
VALUE OilyPNG = rb_define_module("OilyPNG");
|
6
|
+
|
7
|
+
// Setup decoding
|
8
|
+
VALUE OilyPNG_PNGDecoding = rb_define_module_under(OilyPNG, "PNGDecoding");
|
9
|
+
rb_define_method(OilyPNG_PNGDecoding, "decode_png_image_pass", oily_png_decode_png_image_pass, 5);
|
10
|
+
|
11
|
+
// Setup encoding
|
12
|
+
VALUE OilyPNG_PNGEncoding = rb_define_module_under(OilyPNG, "PNGEncoding");
|
13
|
+
rb_define_method(OilyPNG_PNGEncoding, "encode_png_image_pass_to_stream", oily_png_encode_png_image_pass_to_stream, 3);
|
14
|
+
}
|
15
|
+
|
16
|
+
// Returns the number of bytes per pixel for a given color mode.
|
17
|
+
int oily_png_pixel_size(int color_mode) {
|
18
|
+
switch (color_mode) {
|
19
|
+
case OILY_PNG_COLOR_GRAYSCALE: return 1;
|
20
|
+
case OILY_PNG_COLOR_TRUECOLOR: return 3;
|
21
|
+
case OILY_PNG_COLOR_INDEXED: return 1;
|
22
|
+
case OILY_PNG_COLOR_GRAYSCALE_ALPHA: return 2;
|
23
|
+
case OILY_PNG_COLOR_TRUECOLOR_ALPHA: return 4;
|
24
|
+
default: return -1;
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#ifndef OILY_PNG_EXT
|
2
|
+
#define OILY_PNG_EXT
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
// PNG color mode constants
|
7
|
+
#define OILY_PNG_COLOR_GRAYSCALE 0
|
8
|
+
#define OILY_PNG_COLOR_TRUECOLOR 2
|
9
|
+
#define OILY_PNG_COLOR_INDEXED 3
|
10
|
+
#define OILY_PNG_COLOR_GRAYSCALE_ALPHA 4
|
11
|
+
#define OILY_PNG_COLOR_TRUECOLOR_ALPHA 6
|
12
|
+
|
13
|
+
// PNG filter constants
|
14
|
+
#define OILY_PNG_FILTER_NONE 0
|
15
|
+
#define OILY_PNG_FILTER_SUB 1
|
16
|
+
#define OILY_PNG_FILTER_UP 2
|
17
|
+
#define OILY_PNG_FILTER_AVERAGE 3
|
18
|
+
#define OILY_PNG_FILTER_PAETH 4
|
19
|
+
|
20
|
+
// Type definitions
|
21
|
+
#define PIXEL unsigned int // Pixels use 32 bits unsigned integers
|
22
|
+
#define BYTE unsigned char // Bytes use 8 bits unsigned integers
|
23
|
+
|
24
|
+
#include "png_decoding.h"
|
25
|
+
#include "png_encoding.h"
|
26
|
+
|
27
|
+
void Init_oily_png_ext();
|
28
|
+
int oily_png_pixel_size(int color_mode);
|
29
|
+
|
30
|
+
#endif
|
data/ext/oily_png/png_decoding.c
CHANGED
@@ -1,48 +1,9 @@
|
|
1
|
-
#include "
|
2
|
-
|
3
|
-
// PNG color mode constants
|
4
|
-
#define OILY_PNG_COLOR_GRAYSCALE 0
|
5
|
-
#define OILY_PNG_COLOR_TRUECOLOR 2
|
6
|
-
#define OILY_PNG_COLOR_INDEXED 3
|
7
|
-
#define OILY_PNG_COLOR_GRAYSCALE_ALPHA 4
|
8
|
-
#define OILY_PNG_COLOR_TRUECOLOR_ALPHA 6
|
9
|
-
|
10
|
-
// PNG filter constants
|
11
|
-
#define OILY_PNG_FILTER_NONE 0
|
12
|
-
#define OILY_PNG_FILTER_SUB 1
|
13
|
-
#define OILY_PNG_FILTER_UP 2
|
14
|
-
#define OILY_PNG_FILTER_AVERAGE 3
|
15
|
-
#define OILY_PNG_FILTER_PAETH 4
|
16
|
-
|
17
|
-
// Type definitions
|
18
|
-
#define PIXEL unsigned int
|
19
|
-
|
20
|
-
void Init_png_decoding();
|
21
|
-
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE start_pos);
|
1
|
+
#include "oily_png_ext.h"
|
22
2
|
|
23
3
|
////////////////////////////////////////////////////////////////////////////
|
24
4
|
|
25
|
-
// Initialize the extension by creating the OilyPNG::PNGDecoding module
|
26
|
-
void Init_png_decoding() {
|
27
|
-
VALUE OilyPNG = rb_define_module("OilyPNG");
|
28
|
-
VALUE OilyPNGPNGDecoding = rb_define_module_under(OilyPNG, "PNGDecoding");
|
29
|
-
rb_define_method(OilyPNGPNGDecoding, "decode_png_image_pass", oily_png_decode_png_image_pass, 5);
|
30
|
-
}
|
31
|
-
|
32
|
-
// Returns the number of bytes per pixel for a given color mode.
|
33
|
-
int oily_png_pixel_size(color_mode) {
|
34
|
-
switch (color_mode) {
|
35
|
-
case OILY_PNG_COLOR_GRAYSCALE: return 1;
|
36
|
-
case OILY_PNG_COLOR_TRUECOLOR: return 3;
|
37
|
-
case OILY_PNG_COLOR_INDEXED: return 1;
|
38
|
-
case OILY_PNG_COLOR_GRAYSCALE_ALPHA: return 2;
|
39
|
-
case OILY_PNG_COLOR_TRUECOLOR_ALPHA: return 4;
|
40
|
-
default: return -1;
|
41
|
-
}
|
42
|
-
}
|
43
|
-
|
44
5
|
// Decodes a pixel at the given position in the bytearray
|
45
|
-
PIXEL oily_png_decode_pixel(int color_mode,
|
6
|
+
PIXEL oily_png_decode_pixel(int color_mode, BYTE* bytes, int byte_index, VALUE decoding_palette) {
|
46
7
|
switch (color_mode) {
|
47
8
|
case OILY_PNG_COLOR_GRAYSCALE:
|
48
9
|
return (bytes[byte_index] << 24) + (bytes[byte_index] << 16) + (bytes[byte_index] << 8) + 0xff;
|
@@ -60,7 +21,7 @@ PIXEL oily_png_decode_pixel(int color_mode, unsigned char* bytes, int byte_index
|
|
60
21
|
}
|
61
22
|
|
62
23
|
// Decodes a SUB filtered scanline at the given position in the byte array
|
63
|
-
void
|
24
|
+
void oily_png_decode_filter_sub(BYTE* bytes, int pos, int line_length, int pixel_size) {
|
64
25
|
int i;
|
65
26
|
for (i = 1 + pixel_size; i < line_length; i++) {
|
66
27
|
bytes[pos + i] += bytes[pos + i - pixel_size]; // mod 256 ???
|
@@ -68,7 +29,7 @@ void oily_png_filter_sub(unsigned char* bytes, int pos, int line_length, int pix
|
|
68
29
|
}
|
69
30
|
|
70
31
|
// Decodes an UP filtered scanline at the given position in the byte array
|
71
|
-
void
|
32
|
+
void oily_png_decode_filter_up(BYTE* bytes, int pos, int line_length, int pixel_size) {
|
72
33
|
int i;
|
73
34
|
// The first line is not filtered because there is no privous line
|
74
35
|
if (pos >= line_length) {
|
@@ -79,9 +40,9 @@ void oily_png_filter_up(unsigned char* bytes, int pos, int line_length, int pixe
|
|
79
40
|
}
|
80
41
|
|
81
42
|
// Decodes an AVERAGE filtered scanline at the given position in the byte array
|
82
|
-
void
|
43
|
+
void oily_png_decode_filter_average(BYTE* bytes, int pos, int line_length, int pixel_size) {
|
83
44
|
int i;
|
84
|
-
|
45
|
+
BYTE a, b;
|
85
46
|
for (i = 1; i < line_length; i++) {
|
86
47
|
a = (i > pixel_size) ? bytes[pos + i - pixel_size] : 0;
|
87
48
|
b = (pos >= line_length) ? bytes[pos + i - line_length] : 0;
|
@@ -90,8 +51,8 @@ void oily_png_filter_average(unsigned char* bytes, int pos, int line_length, int
|
|
90
51
|
}
|
91
52
|
|
92
53
|
// Decodes a PAETH filtered scanline at the given position in the byte array
|
93
|
-
void
|
94
|
-
|
54
|
+
void oily_png_decode_filter_paeth(BYTE* bytes, int pos, int line_length, int pixel_size) {
|
55
|
+
BYTE a, b, c, pr;
|
95
56
|
int i, p, pa, pb, pc;
|
96
57
|
for (i = 1; i < line_length; i++) {
|
97
58
|
a = (i > pixel_size) ? bytes[pos + i - pixel_size] : 0;
|
@@ -106,9 +67,11 @@ void oily_png_filter_paeth(unsigned char* bytes, int pos, int line_length, int p
|
|
106
67
|
}
|
107
68
|
}
|
108
69
|
|
109
|
-
|
110
|
-
|
111
|
-
|
70
|
+
/*
|
71
|
+
Decodes an image pass from the given byte stream at the given position.
|
72
|
+
A normal PNG will only have one pass that consumes the entire stream, while an
|
73
|
+
interlaced image requires 7 passes which are loaded from different starting positions.
|
74
|
+
*/
|
112
75
|
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE start_pos) {
|
113
76
|
|
114
77
|
int pixel_size = oily_png_pixel_size(FIX2INT(color_mode));
|
@@ -117,19 +80,24 @@ VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALU
|
|
117
80
|
|
118
81
|
VALUE pixels = rb_ary_new();
|
119
82
|
|
120
|
-
|
121
|
-
|
122
|
-
decoding_palette = rb_funcall(self, rb_intern("decoding_palette"), 0);
|
83
|
+
if (RSTRING_LEN(stream) < pass_size + FIX2INT(start_pos)) {
|
84
|
+
exit(1);
|
123
85
|
}
|
124
|
-
|
86
|
+
|
125
87
|
// Copy the bytes for this pass from the stream to a separate location
|
126
88
|
// so we can work on this byte array directly.
|
127
|
-
|
128
|
-
|
89
|
+
BYTE* pixelstream = (BYTE*) RSTRING_PTR(stream);
|
90
|
+
BYTE* bytes = ALLOCA_N(BYTE, pass_size);
|
129
91
|
memcpy(bytes, pixelstream + FIX2INT(start_pos), pass_size);
|
130
92
|
|
93
|
+
// Get the decoding palette for indexed images.
|
94
|
+
VALUE decoding_palette = Qnil;
|
95
|
+
if (FIX2INT(color_mode) == OILY_PNG_COLOR_INDEXED) {
|
96
|
+
decoding_palette = rb_funcall(self, rb_intern("decoding_palette"), 0);
|
97
|
+
}
|
98
|
+
|
131
99
|
int y, x, line_start, prev_line_start, byte_index, pixel_index;
|
132
|
-
|
100
|
+
BYTE filter;
|
133
101
|
PIXEL pixel;
|
134
102
|
|
135
103
|
for (y = 0; y < FIX2INT(height); y++) {
|
@@ -138,10 +106,10 @@ VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALU
|
|
138
106
|
// Apply filering to the line
|
139
107
|
switch (bytes[line_start]) {
|
140
108
|
case OILY_PNG_FILTER_NONE: break;
|
141
|
-
case OILY_PNG_FILTER_SUB:
|
142
|
-
case OILY_PNG_FILTER_UP:
|
143
|
-
case OILY_PNG_FILTER_AVERAGE:
|
144
|
-
case OILY_PNG_FILTER_PAETH:
|
109
|
+
case OILY_PNG_FILTER_SUB: oily_png_decode_filter_sub( bytes, line_start, line_size, pixel_size); break;
|
110
|
+
case OILY_PNG_FILTER_UP: oily_png_decode_filter_up( bytes, line_start, line_size, pixel_size); break;
|
111
|
+
case OILY_PNG_FILTER_AVERAGE: oily_png_decode_filter_average( bytes, line_start, line_size, pixel_size); break;
|
112
|
+
case OILY_PNG_FILTER_PAETH: oily_png_decode_filter_paeth( bytes, line_start, line_size, pixel_size); break;
|
145
113
|
default: exit(1);
|
146
114
|
}
|
147
115
|
|
@@ -157,9 +125,6 @@ VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALU
|
|
157
125
|
}
|
158
126
|
}
|
159
127
|
|
160
|
-
// Get rid of the byte array.
|
161
|
-
free(bytes);
|
162
|
-
|
163
128
|
// Now, return a new ChunkyPNG::Canvas instance with the decoded pixels.
|
164
129
|
return rb_funcall(self, rb_intern("new"), 3, width, height, pixels);
|
165
130
|
}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
#ifndef PNG_DECODING_H
|
2
|
+
#define PNG_DECODING_H
|
3
|
+
|
4
|
+
// Function to overwrite ChunkyPNG::Canvas::PNGDecoding.decode_png_image_pass
|
5
|
+
VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALUE height, VALUE color_mode, VALUE start_pos);
|
6
|
+
|
7
|
+
#endif
|
@@ -0,0 +1,130 @@
|
|
1
|
+
#include "oily_png_ext.h"
|
2
|
+
|
3
|
+
PIXEL oily_png_encode_get_pixel(VALUE self, long index) {
|
4
|
+
VALUE pixels = rb_funcall(self, rb_intern("pixels"), 0);
|
5
|
+
return NUM2UINT(rb_ary_entry(pixels, index));
|
6
|
+
}
|
7
|
+
|
8
|
+
void oily_png_encode_pixel(PIXEL pixel, int color_mode, BYTE* bytes, int pos, VALUE palette) {
|
9
|
+
switch (color_mode) {
|
10
|
+
case OILY_PNG_COLOR_GRAYSCALE:
|
11
|
+
bytes[pos] = (BYTE) ((pixel & (PIXEL) 0xff000000) >> 24);
|
12
|
+
break;
|
13
|
+
case OILY_PNG_COLOR_TRUECOLOR:
|
14
|
+
bytes[pos + 0] = (BYTE) ((pixel & (PIXEL) 0xff000000) >> 24);
|
15
|
+
bytes[pos + 1] = (BYTE) ((pixel & (PIXEL) 0x00ff0000) >> 16);
|
16
|
+
bytes[pos + 2] = (BYTE) ((pixel & (PIXEL) 0x0000ff00) >> 8);
|
17
|
+
break;
|
18
|
+
case OILY_PNG_COLOR_INDEXED:
|
19
|
+
bytes[pos] = (BYTE) NUM2UINT(rb_funcall(palette, rb_intern("index"), 1, UINT2NUM(pixel)));
|
20
|
+
break;
|
21
|
+
case OILY_PNG_COLOR_GRAYSCALE_ALPHA:
|
22
|
+
bytes[pos + 0] = (BYTE) ((pixel & (PIXEL) 0xff000000) >> 24);
|
23
|
+
bytes[pos + 1] = (BYTE) ((pixel & (PIXEL) 0x000000ff));
|
24
|
+
break;
|
25
|
+
case OILY_PNG_COLOR_TRUECOLOR_ALPHA:
|
26
|
+
bytes[pos + 0] = (BYTE) ((pixel & (PIXEL) 0xff000000) >> 24);
|
27
|
+
bytes[pos + 1] = (BYTE) ((pixel & (PIXEL) 0x00ff0000) >> 16);
|
28
|
+
bytes[pos + 2] = (BYTE) ((pixel & (PIXEL) 0x0000ff00) >> 8);
|
29
|
+
bytes[pos + 3] = (BYTE) ((pixel & (PIXEL) 0x000000ff));
|
30
|
+
break;
|
31
|
+
default:
|
32
|
+
exit(1);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
void oily_png_encode_filter_sub(BYTE* bytes, int pos, int line_size, int pixel_size) {
|
37
|
+
int x;
|
38
|
+
for (x = line_size - 1; x > pixel_size; x--) {
|
39
|
+
bytes[pos + x] -= bytes[pos + x - pixel_size];
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
void oily_png_encode_filter_up(BYTE* bytes, int pos, int line_size, int pixel_size) {
|
44
|
+
int x;
|
45
|
+
if (pos >= line_size) {
|
46
|
+
for (x = line_size - 1; x > 0; x--) {
|
47
|
+
bytes[pos + x] -= bytes[pos + x - line_size];
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
void oily_png_encode_filter_average(BYTE* bytes, int pos, int line_size, int pixel_size) {
|
53
|
+
int x; BYTE a, b;
|
54
|
+
for (x = line_size - 1; x > 0; x--) {
|
55
|
+
a = (x > pixel_size) ? bytes[pos + x - pixel_size] : 0;
|
56
|
+
b = (pos >= line_size) ? bytes[pos + x - line_size] : 0;
|
57
|
+
bytes[pos + x] -= ((a + b) >> 1);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
void oily_png_encode_filter_paeth(BYTE* bytes, int pos, int line_size, int pixel_size) {
|
62
|
+
int x, p, pa, pb, pc; BYTE a, b, c, pr;
|
63
|
+
for (x = line_size - 1; x > 0; x--) {
|
64
|
+
a = (x > pixel_size) ? bytes[pos + x - pixel_size] : 0;
|
65
|
+
b = (pos >= line_size) ? bytes[pos + x - line_size] : 0;
|
66
|
+
c = (pos >= line_size && x > pixel_size) ? bytes[pos + x - line_size - pixel_size] : 0;
|
67
|
+
p = a + b - c;
|
68
|
+
pa = abs(p - a);
|
69
|
+
pb = abs(p - b);
|
70
|
+
pc = abs(p - c);
|
71
|
+
pr = (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
|
72
|
+
bytes[pos + x] -= pr;
|
73
|
+
}
|
74
|
+
|
75
|
+
}
|
76
|
+
|
77
|
+
|
78
|
+
/*
|
79
|
+
Encodes an image and append it to the stream.
|
80
|
+
A normal PNG will only have one pass and call this method once, while interlaced
|
81
|
+
images are split up in 7 distinct images. This method will be called for every one
|
82
|
+
of these images, reusing the stream.
|
83
|
+
*/
|
84
|
+
VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE color_mode, VALUE filtering) {
|
85
|
+
|
86
|
+
// Get the data
|
87
|
+
int width = FIX2INT(rb_funcall(self, rb_intern("width"), 0));
|
88
|
+
int height = FIX2INT(rb_funcall(self, rb_intern("height"), 0));
|
89
|
+
VALUE pixels = rb_funcall(self, rb_intern("pixels"), 0);
|
90
|
+
|
91
|
+
VALUE palette = Qnil;
|
92
|
+
if (FIX2INT(color_mode) == OILY_PNG_COLOR_INDEXED) {
|
93
|
+
palette = rb_funcall(self, rb_intern("encoding_palette"), 0);
|
94
|
+
}
|
95
|
+
|
96
|
+
int pixel_size = oily_png_pixel_size(FIX2INT(color_mode));
|
97
|
+
int line_size = 1 + pixel_size * width;
|
98
|
+
int pass_size = line_size * height;
|
99
|
+
|
100
|
+
// Allocate memory for the byte array.
|
101
|
+
BYTE* bytes = ALLOCA_N(BYTE, pass_size);
|
102
|
+
|
103
|
+
PIXEL pixel;
|
104
|
+
int x, y, pos;
|
105
|
+
for (y = 0; y < height; y++) {
|
106
|
+
bytes[line_size * y] = FIX2INT(filtering);
|
107
|
+
|
108
|
+
for (x = 0; x < width; x++) {
|
109
|
+
pixel = NUM2UINT(rb_ary_entry(pixels, y * height + x));
|
110
|
+
pos = (line_size * y) + (pixel_size * x) + 1;
|
111
|
+
oily_png_encode_pixel(pixel, FIX2INT(color_mode), bytes, pos, palette);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
if (FIX2INT(filtering) != OILY_PNG_FILTER_NONE) {
|
116
|
+
for (y = height - 1; y >= 0; y--) {
|
117
|
+
switch (FIX2INT(filtering)) {
|
118
|
+
case OILY_PNG_FILTER_SUB: oily_png_encode_filter_sub( bytes, line_size * y, line_size, pixel_size); break;
|
119
|
+
case OILY_PNG_FILTER_UP: oily_png_encode_filter_up( bytes, line_size * y, line_size, pixel_size); break;
|
120
|
+
case OILY_PNG_FILTER_AVERAGE: oily_png_encode_filter_average( bytes, line_size * y, line_size, pixel_size); break;
|
121
|
+
case OILY_PNG_FILTER_PAETH: oily_png_encode_filter_paeth( bytes, line_size * y, line_size, pixel_size); break;
|
122
|
+
default: exit(1);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
rb_str_cat(stream, bytes, pass_size);
|
128
|
+
|
129
|
+
return Qnil;
|
130
|
+
}
|
data/lib/oily_png.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require 'chunky_png'
|
2
|
-
require 'oily_png/png_decoding'
|
3
2
|
|
4
3
|
module OilyPNG
|
5
4
|
|
6
|
-
VERSION = "0.0.
|
5
|
+
VERSION = "0.0.4"
|
7
6
|
|
8
7
|
def self.included(base)
|
9
8
|
base::Canvas.extend OilyPNG::PNGDecoding
|
9
|
+
base::Canvas.include OilyPNG::PNGEncoding
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|
13
13
|
|
14
|
+
require 'oily_png/oily_png_ext'
|
15
|
+
|
16
|
+
# Include mixin into ChunkyPNG
|
14
17
|
ChunkyPNG.send(:include, OilyPNG)
|
data/oily_png.gemspec
CHANGED
@@ -4,7 +4,7 @@ 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.0.
|
7
|
+
s.version = "0.0.4"
|
8
8
|
s.date = "2010-10-05"
|
9
9
|
|
10
10
|
s.summary = "Native mixin to speed up ChunkyPNG"
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.require_paths = ["lib", "ext"]
|
21
21
|
|
22
22
|
s.required_rubygems_version = '1.3.7'
|
23
|
-
s.add_runtime_dependency('chunky_png', '~> 0.10.
|
23
|
+
s.add_runtime_dependency('chunky_png', '~> 0.10.2')
|
24
24
|
|
25
25
|
s.add_development_dependency('rake')
|
26
26
|
s.add_development_dependency('rspec', '>= 1.3')
|
@@ -30,6 +30,6 @@ Gem::Specification.new do |s|
|
|
30
30
|
|
31
31
|
# Do not change the files and test_files fields by hand. This will be done
|
32
32
|
# automatically by the gem release script.
|
33
|
-
s.files = %w(.gitignore Gemfile Gemfile.lock LICENSE README.rdoc Rakefile ext/oily_png/extconf.rb ext/oily_png/png_decoding.c lib/oily_png.rb oily_png.gemspec spec/decoding_spec.rb spec/resources/gray.png spec/resources/operations.png spec/spec_helper.rb tasks/github-gem.rake)
|
34
|
-
s.test_files = %w(spec/decoding_spec.rb)
|
33
|
+
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/operations.png spec/spec_helper.rb tasks/github-gem.rake)
|
34
|
+
s.test_files = %w(spec/decoding_spec.rb spec/encoding_spec.rb)
|
35
35
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe OilyPNG::PNGEncoding do
|
4
|
+
|
5
|
+
context 'encoding different color modes' do
|
6
|
+
before do
|
7
|
+
@canvas = ChunkyPNG::Canvas.from_file(resource_file('gray.png'))
|
8
|
+
@oily_canvas = OilyCanvas.from_canvas(@canvas)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should encode an image using grayscale correctly" do
|
12
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_GRAYSCALE, ChunkyPNG::FILTER_NONE)
|
13
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_GRAYSCALE, ChunkyPNG::FILTER_NONE)
|
14
|
+
stream1.should == stream2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should encode an image using grayscale alpha correctly" do
|
18
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_GRAYSCALE_ALPHA, ChunkyPNG::FILTER_NONE)
|
19
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_GRAYSCALE_ALPHA, ChunkyPNG::FILTER_NONE)
|
20
|
+
stream1.should == stream2
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should encode an image using truecolor correctly" do
|
24
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_NONE)
|
25
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_NONE)
|
26
|
+
stream1.should == stream2
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should encode an image using truecolor alpha correctly" do
|
30
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_NONE)
|
31
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR_ALPHA, ChunkyPNG::FILTER_NONE)
|
32
|
+
stream1.should == stream2
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should encode an image using indexed colors correctly" do
|
36
|
+
# Setup an encoding palette first
|
37
|
+
mock_palette = mock('palette', :index => 0xab)
|
38
|
+
@canvas.stub(:encoding_palette).and_return(mock_palette)
|
39
|
+
@oily_canvas.stub(:encoding_palette).and_return(mock_palette)
|
40
|
+
|
41
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_INDEXED, ChunkyPNG::FILTER_NONE)
|
42
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_INDEXED, ChunkyPNG::FILTER_NONE)
|
43
|
+
stream1.should == stream2
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'encoding different filters' do
|
48
|
+
before do
|
49
|
+
@canvas = ChunkyPNG::Canvas.from_file(resource_file('operations.png'))
|
50
|
+
@oily_canvas = OilyCanvas.from_canvas(@canvas)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should encode correctly with no filtering" do
|
54
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_NONE)
|
55
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_NONE)
|
56
|
+
stream1.should == stream2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should encode correctly with sub filtering" do
|
60
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_SUB)
|
61
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_SUB)
|
62
|
+
stream1.should == stream2
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should encode correctly with up filtering" do
|
66
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_UP)
|
67
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_UP)
|
68
|
+
stream1.should == stream2
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should encode correctly with average filtering" do
|
72
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_AVERAGE)
|
73
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_AVERAGE)
|
74
|
+
stream1.should == stream2
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should encode correctly with paeth filtering" do
|
78
|
+
@oily_canvas.send(:encode_png_image_pass_to_stream, stream1 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_PAETH)
|
79
|
+
@canvas.send(:encode_png_image_pass_to_stream, stream2 = "", ChunkyPNG::COLOR_TRUECOLOR, ChunkyPNG::FILTER_PAETH)
|
80
|
+
stream1.should == stream2
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,10 +5,11 @@ Bundler.setup
|
|
5
5
|
|
6
6
|
require 'spec'
|
7
7
|
require 'chunky_png'
|
8
|
-
require 'oily_png/
|
8
|
+
require 'oily_png/oily_png_ext'
|
9
9
|
|
10
10
|
class OilyCanvas < ChunkyPNG::Canvas
|
11
11
|
extend OilyPNG::PNGDecoding
|
12
|
+
include OilyPNG::PNGEncoding
|
12
13
|
end
|
13
14
|
|
14
15
|
module ResourceHelper
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oily_png
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 4
|
10
|
+
version: 0.0.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Willem van Bergen
|
@@ -24,12 +24,12 @@ dependencies:
|
|
24
24
|
requirements:
|
25
25
|
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
hash:
|
27
|
+
hash: 51
|
28
28
|
segments:
|
29
29
|
- 0
|
30
30
|
- 10
|
31
|
-
-
|
32
|
-
version: 0.10.
|
31
|
+
- 2
|
32
|
+
version: 0.10.2
|
33
33
|
requirement: *id001
|
34
34
|
name: chunky_png
|
35
35
|
prerelease: false
|
@@ -80,10 +80,16 @@ files:
|
|
80
80
|
- README.rdoc
|
81
81
|
- Rakefile
|
82
82
|
- ext/oily_png/extconf.rb
|
83
|
+
- ext/oily_png/oily_png_ext.c
|
84
|
+
- ext/oily_png/oily_png_ext.h
|
83
85
|
- ext/oily_png/png_decoding.c
|
86
|
+
- ext/oily_png/png_decoding.h
|
87
|
+
- ext/oily_png/png_encoding.c
|
88
|
+
- ext/oily_png/png_encoding.h
|
84
89
|
- lib/oily_png.rb
|
85
90
|
- oily_png.gemspec
|
86
91
|
- spec/decoding_spec.rb
|
92
|
+
- spec/encoding_spec.rb
|
87
93
|
- spec/resources/gray.png
|
88
94
|
- spec/resources/operations.png
|
89
95
|
- spec/spec_helper.rb
|
@@ -132,3 +138,4 @@ specification_version: 3
|
|
132
138
|
summary: Native mixin to speed up ChunkyPNG
|
133
139
|
test_files:
|
134
140
|
- spec/decoding_spec.rb
|
141
|
+
- spec/encoding_spec.rb
|