oily_png 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.rdoc +3 -1
- data/ext/oily_png/png_decoding.c +1 -1
- data/ext/oily_png/png_encoding.c +57 -35
- data/lib/oily_png.rb +1 -1
- data/oily_png.gemspec +2 -2
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
OilyPNG is a Ruby C extension to speed up the pure Ruby ChunkyPNG library. It is a standalone
|
4
4
|
module, so it does not require LibPNG, ImageMagick or any other library. Currently it has an
|
5
5
|
alternative implementation of decoding and encoding PNGs, making these operations much
|
6
|
-
faster for PNG images that apply filtering.
|
6
|
+
faster, especially for PNG images that apply filtering.
|
7
|
+
|
8
|
+
Performance comparison: http://gist.github.com/611255
|
7
9
|
|
8
10
|
*Warning*: this is my first C code in years. It may blow up your PC after leaking memory all
|
9
11
|
over the place, killing a kitten in the process. You have been warned.
|
data/ext/oily_png/png_decoding.c
CHANGED
@@ -94,7 +94,7 @@ VALUE oily_png_decode_png_image_pass(VALUE self, VALUE stream, VALUE width, VALU
|
|
94
94
|
}
|
95
95
|
|
96
96
|
// Select the pixel decoder function for this color mode.
|
97
|
-
PIXEL (*pixel_decoder)(int, BYTE*, int, VALUE);
|
97
|
+
PIXEL (*pixel_decoder)(int, BYTE*, int, VALUE) = NULL;
|
98
98
|
switch (FIX2INT(color_mode)) {
|
99
99
|
case OILY_PNG_COLOR_GRAYSCALE: pixel_decoder = &oily_png_decode_pixel_grayscale; break;
|
100
100
|
case OILY_PNG_COLOR_TRUECOLOR: pixel_decoder = &oily_png_decode_pixel_truecolor; break;
|
data/ext/oily_png/png_encoding.c
CHANGED
@@ -1,33 +1,35 @@
|
|
1
1
|
#include "oily_png_ext.h"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
break;
|
8
|
-
case OILY_PNG_COLOR_TRUECOLOR:
|
9
|
-
bytes[pos + 0] = R_BYTE(pixel);
|
10
|
-
bytes[pos + 1] = G_BYTE(pixel);
|
11
|
-
bytes[pos + 2] = B_BYTE(pixel);
|
12
|
-
break;
|
13
|
-
case OILY_PNG_COLOR_INDEXED:
|
14
|
-
bytes[pos] = (BYTE) NUM2UINT(rb_funcall(palette, rb_intern("index"), 1, UINT2NUM(pixel)));
|
15
|
-
break;
|
16
|
-
case OILY_PNG_COLOR_GRAYSCALE_ALPHA:
|
17
|
-
bytes[pos + 0] = R_BYTE(pixel);
|
18
|
-
bytes[pos + 1] = A_BYTE(pixel);
|
19
|
-
break;
|
20
|
-
case OILY_PNG_COLOR_TRUECOLOR_ALPHA:
|
21
|
-
bytes[pos + 0] = R_BYTE(pixel);
|
22
|
-
bytes[pos + 1] = G_BYTE(pixel);
|
23
|
-
bytes[pos + 2] = B_BYTE(pixel);
|
24
|
-
bytes[pos + 3] = A_BYTE(pixel);
|
25
|
-
break;
|
26
|
-
default:
|
27
|
-
rb_raise(rb_eRuntimeError, "Unsupported color mode: %d", color_mode);
|
28
|
-
}
|
3
|
+
///// Pixel encoding functions //////////////////////////////////////////
|
4
|
+
|
5
|
+
void oily_png_encode_pixel_grayscale(PIXEL pixel, BYTE* bytes, int pos, VALUE palette) {
|
6
|
+
bytes[pos] = R_BYTE(pixel);
|
29
7
|
}
|
30
8
|
|
9
|
+
void oily_png_encode_pixel_grayscale_alpha(PIXEL pixel, BYTE* bytes, int pos, VALUE palette) {
|
10
|
+
bytes[pos + 0] = R_BYTE(pixel);
|
11
|
+
bytes[pos + 1] = A_BYTE(pixel);
|
12
|
+
}
|
13
|
+
|
14
|
+
void oily_png_encode_pixel_truecolor(PIXEL pixel, BYTE* bytes, int pos, VALUE palette) {
|
15
|
+
bytes[pos + 0] = R_BYTE(pixel);
|
16
|
+
bytes[pos + 1] = G_BYTE(pixel);
|
17
|
+
bytes[pos + 2] = B_BYTE(pixel);
|
18
|
+
}
|
19
|
+
|
20
|
+
void oily_png_encode_pixel_truecolor_alpha(PIXEL pixel, BYTE* bytes, int pos, VALUE palette) {
|
21
|
+
bytes[pos + 0] = R_BYTE(pixel);
|
22
|
+
bytes[pos + 1] = G_BYTE(pixel);
|
23
|
+
bytes[pos + 2] = B_BYTE(pixel);
|
24
|
+
bytes[pos + 3] = A_BYTE(pixel);
|
25
|
+
}
|
26
|
+
|
27
|
+
void oily_png_encode_pixel_indexed(PIXEL pixel, BYTE* bytes, int pos, VALUE palette) {
|
28
|
+
bytes[pos] = (BYTE) NUM2UINT(rb_funcall(palette, rb_intern("index"), 1, UINT2NUM(pixel)));
|
29
|
+
}
|
30
|
+
|
31
|
+
///// Scanline filtering functions //////////////////////////////////////////
|
32
|
+
|
31
33
|
void oily_png_encode_filter_sub(BYTE* bytes, int pos, int line_size, int pixel_size) {
|
32
34
|
int x;
|
33
35
|
for (x = line_size - 1; x > pixel_size; x--) {
|
@@ -66,7 +68,6 @@ void oily_png_encode_filter_paeth(BYTE* bytes, int pos, int line_size, int pixel
|
|
66
68
|
pr = (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
|
67
69
|
FILTER_BYTE(bytes[pos + x], pr);
|
68
70
|
}
|
69
|
-
|
70
71
|
}
|
71
72
|
|
72
73
|
VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE color_mode, VALUE filtering) {
|
@@ -80,6 +81,7 @@ VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE c
|
|
80
81
|
rb_raise(rb_eRuntimeError, "The number of pixels does not match the canvas dimensions.");
|
81
82
|
}
|
82
83
|
|
84
|
+
// Get the encoding palette if we're encoding to an indexed bytestream.
|
83
85
|
VALUE palette = Qnil;
|
84
86
|
if (FIX2INT(color_mode) == OILY_PNG_COLOR_INDEXED) {
|
85
87
|
palette = rb_funcall(self, rb_intern("encoding_palette"), 0);
|
@@ -92,6 +94,18 @@ VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE c
|
|
92
94
|
// Allocate memory for the byte array.
|
93
95
|
BYTE* bytes = ALLOCA_N(BYTE, pass_size);
|
94
96
|
|
97
|
+
// Select out pixel encoder function based on the color mode.
|
98
|
+
void (*pixel_encoder)(PIXEL, BYTE*, int, VALUE) = NULL;
|
99
|
+
switch (FIX2INT(color_mode)) {
|
100
|
+
case OILY_PNG_COLOR_GRAYSCALE: pixel_encoder = &oily_png_encode_pixel_grayscale; break;
|
101
|
+
case OILY_PNG_COLOR_TRUECOLOR: pixel_encoder = &oily_png_encode_pixel_truecolor; break;
|
102
|
+
case OILY_PNG_COLOR_INDEXED: pixel_encoder = &oily_png_encode_pixel_indexed; break;
|
103
|
+
case OILY_PNG_COLOR_GRAYSCALE_ALPHA: pixel_encoder = &oily_png_encode_pixel_grayscale_alpha; break;
|
104
|
+
case OILY_PNG_COLOR_TRUECOLOR_ALPHA: pixel_encoder = &oily_png_encode_pixel_truecolor_alpha; break;
|
105
|
+
default: rb_raise(rb_eRuntimeError, "Unsupported color mode: %d", color_mode);
|
106
|
+
}
|
107
|
+
|
108
|
+
// Loop over all the pixels to encode them into the byte array.
|
95
109
|
PIXEL pixel;
|
96
110
|
int x, y, pos;
|
97
111
|
for (y = 0; y < height; y++) {
|
@@ -100,22 +114,30 @@ VALUE oily_png_encode_png_image_pass_to_stream(VALUE self, VALUE stream, VALUE c
|
|
100
114
|
for (x = 0; x < width; x++) {
|
101
115
|
pixel = NUM2UINT(rb_ary_entry(pixels, y * height + x));
|
102
116
|
pos = (line_size * y) + (pixel_size * x) + 1;
|
103
|
-
|
117
|
+
pixel_encoder(pixel, bytes, pos, palette);
|
104
118
|
}
|
105
119
|
}
|
106
120
|
|
121
|
+
// Check if we are going to apply any filtering
|
107
122
|
if (FIX2INT(filtering) != OILY_PNG_FILTER_NONE) {
|
123
|
+
|
124
|
+
// Assign the chosen filter function to the scanline_filter variable.
|
125
|
+
void (*scanline_filter)(BYTE*, int, int, int) = NULL;
|
126
|
+
switch (FIX2INT(filtering)) {
|
127
|
+
case OILY_PNG_FILTER_SUB: scanline_filter = &oily_png_encode_filter_sub; break;
|
128
|
+
case OILY_PNG_FILTER_UP: scanline_filter = &oily_png_encode_filter_up; break;
|
129
|
+
case OILY_PNG_FILTER_AVERAGE: scanline_filter = &oily_png_encode_filter_average; break;
|
130
|
+
case OILY_PNG_FILTER_PAETH: scanline_filter = &oily_png_encode_filter_paeth; break;
|
131
|
+
default: rb_raise(rb_eRuntimeError, "Unsupported filter type: %d", FIX2INT(filtering));
|
132
|
+
}
|
133
|
+
|
134
|
+
// Now, apply the scanline_filter function to every line, backwards.
|
108
135
|
for (y = height - 1; y >= 0; y--) {
|
109
|
-
|
110
|
-
case OILY_PNG_FILTER_SUB: oily_png_encode_filter_sub( bytes, line_size * y, line_size, pixel_size); break;
|
111
|
-
case OILY_PNG_FILTER_UP: oily_png_encode_filter_up( bytes, line_size * y, line_size, pixel_size); break;
|
112
|
-
case OILY_PNG_FILTER_AVERAGE: oily_png_encode_filter_average( bytes, line_size * y, line_size, pixel_size); break;
|
113
|
-
case OILY_PNG_FILTER_PAETH: oily_png_encode_filter_paeth( bytes, line_size * y, line_size, pixel_size); break;
|
114
|
-
default: rb_raise(rb_eRuntimeError, "Unsupported filter type: %d", FIX2INT(filtering));
|
115
|
-
}
|
136
|
+
scanline_filter(bytes, line_size * y, line_size, pixel_size);
|
116
137
|
}
|
117
138
|
}
|
118
139
|
|
140
|
+
// Append to encoded image pass to the output stream.
|
119
141
|
rb_str_cat(stream, (char*) bytes, pass_size);
|
120
142
|
return Qnil;
|
121
143
|
}
|
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.0.
|
8
|
-
s.date = "2010-10-
|
7
|
+
s.version = "0.0.7"
|
8
|
+
s.date = "2010-10-07"
|
9
9
|
|
10
10
|
s.summary = "Native mixin to speed up ChunkyPNG"
|
11
11
|
s.description = <<-EOT
|
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: 17
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Willem van Bergen
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-10-
|
18
|
+
date: 2010-10-07 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|