paulnicholson-acrylic 0.1.0
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/README +0 -0
- data/Rakefile +28 -0
- data/TODO +19 -0
- data/VERSION.yml +4 -0
- data/ext/image_surface_extensions/extconf.rb +11 -0
- data/ext/image_surface_extensions/native_image_surface_extensions.c +344 -0
- data/lib/acrylic.rb +6 -0
- data/lib/border_tools.rb +121 -0
- data/lib/cairo_tools.rb +200 -0
- data/lib/color.rb +149 -0
- data/lib/core_ext.rb +16 -0
- data/lib/curve.rb +120 -0
- data/lib/image_generator.rb +79 -0
- data/lib/image_surface_extensions.rb +14 -0
- data/lib/pascal.rb +32 -0
- data/lib/shape.rb +14 -0
- data/lib/text_box.rb +96 -0
- data/test/bump_map_test.rb +60 -0
- data/test/cairo_tools_test.rb +36 -0
- data/test/color_test.rb +71 -0
- data/test/surface.png +0 -0
- data/test/test_helper.rb +16 -0
- metadata +85 -0
data/README
ADDED
|
File without changes
|
data/Rakefile
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'jeweler'
|
|
4
|
+
Jeweler::Tasks.new do |s|
|
|
5
|
+
s.name = "acrylic"
|
|
6
|
+
# s.executables = "acrylic"
|
|
7
|
+
s.summary = "Photoshop for cool people."
|
|
8
|
+
# s.email = ""
|
|
9
|
+
s.homepage = "http://github.com/dotjerky/acrylic"
|
|
10
|
+
s.description = "A set of image manipulation tools built on top of Cairo"
|
|
11
|
+
s.authors = ["Austin Taylor", "Paul Nicholson"]
|
|
12
|
+
s.files = FileList["[A-Z]*", "{bin,lib,test}/**/*", "ext/**/*.{c,rb}"]
|
|
13
|
+
s.autorequire = "acrylic"
|
|
14
|
+
s.extensions = FileList["ext/**/extconf.rb"]
|
|
15
|
+
s.add_dependency('activesupport')
|
|
16
|
+
end
|
|
17
|
+
rescue LoadError
|
|
18
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
require 'rake'
|
|
22
|
+
require 'rake/testtask'
|
|
23
|
+
require 'rake/rdoctask'
|
|
24
|
+
|
|
25
|
+
Rake::TestTask.new(:default) do |t|
|
|
26
|
+
t.libs << "test"
|
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
|
28
|
+
end
|
data/TODO
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
drawing:
|
|
2
|
+
- width controls (calligraphy)
|
|
3
|
+
- mirroring
|
|
4
|
+
|
|
5
|
+
surface:
|
|
6
|
+
- bump maps
|
|
7
|
+
- clouds (fractal-controlled noise)
|
|
8
|
+
- noise
|
|
9
|
+
- squiggle (how do you do this?)
|
|
10
|
+
- brushed metal (horizontally blurred noise?)
|
|
11
|
+
- wood (is this worth trying to generate? squiggled brushed metal?)
|
|
12
|
+
- leather (squiggled and blurred hexagons?)
|
|
13
|
+
|
|
14
|
+
factoring:
|
|
15
|
+
- tools for image compositing/slicing (capture_image, etc)
|
|
16
|
+
- layer stuff
|
|
17
|
+
- permutations (variations)
|
|
18
|
+
- better syntax for parameter variations
|
|
19
|
+
- better manipulation of paths (rounding, etc)
|
data/VERSION.yml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
require 'rbconfig'
|
|
3
|
+
|
|
4
|
+
have_header 'stdlib.h'
|
|
5
|
+
have_header 'ruby.h'
|
|
6
|
+
have_header 'intern.h'
|
|
7
|
+
have_library 'cairo'
|
|
8
|
+
find_header 'cairo.h', "#{Config::expand(CONFIG['includedir'])}/cairo"
|
|
9
|
+
find_header 'rb_cairo.h', Config::expand(CONFIG['sitearchdir'])
|
|
10
|
+
|
|
11
|
+
create_makefile('native_image_surface_extensions')
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#include "ruby.h"
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <cairo.h>
|
|
4
|
+
#include <rb_cairo.h>
|
|
5
|
+
#include <intern.h>
|
|
6
|
+
|
|
7
|
+
int zero[1] = {1};
|
|
8
|
+
int one[3] = {1, 2, 1};
|
|
9
|
+
int two[5] = {1, 4, 6, 4, 1};
|
|
10
|
+
int three[7] = {1, 6, 15, 20, 15, 6, 1};
|
|
11
|
+
int four[9] = {1, 8, 28, 56, 70, 56, 28, 8, 1};
|
|
12
|
+
int five[11] = {1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1};
|
|
13
|
+
int six[13] = {1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1};
|
|
14
|
+
int seven[15] = {1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1};
|
|
15
|
+
int eight[17] = {1, 16, 120, 560, 1820, 4368, 8008, 11440, 12870, 11440, 8008, 4368, 1820, 560, 120, 16, 1};
|
|
16
|
+
int nine[19] = {1, 18, 153, 816, 3060, 8568, 18564, 31824, 43758, 48620, 43758, 31824, 18564, 8568, 3060, 816, 153, 18, 1};
|
|
17
|
+
int ten[21] = {1, 20, 190, 1140, 4845, 15504, 38760, 77520, 125970, 167960, 184756, 167960, 125970, 77520, 38760, 15504, 4845, 1140, 190, 20, 1};
|
|
18
|
+
int *triangle[11] = {zero, one, two, three, four, five, six, seven, eight, nine, ten};
|
|
19
|
+
int sums[11] = {1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576};
|
|
20
|
+
|
|
21
|
+
// cr.blur(radius)
|
|
22
|
+
static VALUE method_blur(VALUE self, VALUE _radius) {
|
|
23
|
+
int radius = FIX2INT(_radius);
|
|
24
|
+
|
|
25
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
26
|
+
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
27
|
+
int width = cairo_image_surface_get_width(surface);
|
|
28
|
+
int height = cairo_image_surface_get_height(surface);
|
|
29
|
+
int stride = cairo_image_surface_get_stride(surface);
|
|
30
|
+
int length = height*stride;
|
|
31
|
+
|
|
32
|
+
cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
33
|
+
unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
|
|
34
|
+
|
|
35
|
+
unsigned char *color;
|
|
36
|
+
double sumr, sumg, sumb, suma;
|
|
37
|
+
int gauss_w = radius*2 + 1;
|
|
38
|
+
int *mask = triangle[radius];
|
|
39
|
+
int gauss_sum = sums[radius];
|
|
40
|
+
int i, j, k, x, y;
|
|
41
|
+
for (i = 0; i < height; i++) {
|
|
42
|
+
for (j = 0; j < width; j++) {
|
|
43
|
+
sumr = sumg = sumb = suma = 0;
|
|
44
|
+
for (k = 0; k < gauss_w; k++) {
|
|
45
|
+
y = i-radius+k;
|
|
46
|
+
if (y > height || y < 0) continue;
|
|
47
|
+
color = data + y*stride + j*4;
|
|
48
|
+
if (color < data || color > data + length) continue;
|
|
49
|
+
suma += color[0]*mask[k];
|
|
50
|
+
sumr += color[1]*mask[k];
|
|
51
|
+
sumg += color[2]*mask[k];
|
|
52
|
+
sumb += color[3]*mask[k];
|
|
53
|
+
}
|
|
54
|
+
color = tmp_data + i*stride + j*4;
|
|
55
|
+
color[0] = suma/gauss_sum;
|
|
56
|
+
color[1] = sumr/gauss_sum;
|
|
57
|
+
color[2] = sumg/gauss_sum;
|
|
58
|
+
color[3] = sumb/gauss_sum;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (i = 0; i < height; i++) {
|
|
62
|
+
for (j = 0; j < width; j++) {
|
|
63
|
+
sumr = sumg = sumb = suma = 0;
|
|
64
|
+
for (k = 0; k < gauss_w; k++) {
|
|
65
|
+
int x = j-radius+k;
|
|
66
|
+
if (x > width || x < 0) continue;
|
|
67
|
+
color = tmp_data + i*stride + x*4;
|
|
68
|
+
if (color < tmp_data || color > tmp_data + length) continue;
|
|
69
|
+
suma += color[0]*mask[k];
|
|
70
|
+
sumr += color[1]*mask[k];
|
|
71
|
+
sumg += color[2]*mask[k];
|
|
72
|
+
sumb += color[3]*mask[k];
|
|
73
|
+
}
|
|
74
|
+
color = data + i*stride + j*4;
|
|
75
|
+
color[0] = suma/gauss_sum;
|
|
76
|
+
color[1] = sumr/gauss_sum;
|
|
77
|
+
color[2] = sumg/gauss_sum;
|
|
78
|
+
color[3] = sumb/gauss_sum;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Qnil;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// cr.vertical_blur(radius)
|
|
85
|
+
static VALUE method_vertical_blur(VALUE self, VALUE _radius) {
|
|
86
|
+
int radius = FIX2INT(_radius);
|
|
87
|
+
|
|
88
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
89
|
+
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
90
|
+
int width = cairo_image_surface_get_width(surface);
|
|
91
|
+
int height = cairo_image_surface_get_height(surface);
|
|
92
|
+
int stride = cairo_image_surface_get_stride(surface);
|
|
93
|
+
int length = height*stride;
|
|
94
|
+
|
|
95
|
+
cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
96
|
+
unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
|
|
97
|
+
|
|
98
|
+
unsigned char *color;
|
|
99
|
+
unsigned char *color2;
|
|
100
|
+
double sumr, sumg, sumb, suma;
|
|
101
|
+
int gauss_w = radius*2 + 1;
|
|
102
|
+
int *mask = triangle[radius];
|
|
103
|
+
int gauss_sum = sums[radius];
|
|
104
|
+
int i, j, k, x, y;
|
|
105
|
+
for (i = 0; i < height; i++) {
|
|
106
|
+
for (j = 0; j < width; j++) {
|
|
107
|
+
color = data + i*stride + j*4;
|
|
108
|
+
if (color < data || color > data + length) continue;
|
|
109
|
+
color2 = tmp_data + i*stride + j*4;
|
|
110
|
+
color2[0] = color[0];
|
|
111
|
+
color2[1] = color[1];
|
|
112
|
+
color2[2] = color[2];
|
|
113
|
+
color2[3] = color[3];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (i = 0; i < height; i++) {
|
|
117
|
+
for (j = 0; j < width; j++) {
|
|
118
|
+
sumr = sumg = sumb = suma = 0;
|
|
119
|
+
for (k = 0; k < gauss_w; k++) {
|
|
120
|
+
y = i-radius+k;
|
|
121
|
+
if (y > height || y < 0) continue;
|
|
122
|
+
color = data + y*stride + j*4;
|
|
123
|
+
if (color < data || color > data + length) continue;
|
|
124
|
+
suma += color[0]*mask[k];
|
|
125
|
+
sumr += color[1]*mask[k];
|
|
126
|
+
sumg += color[2]*mask[k];
|
|
127
|
+
sumb += color[3]*mask[k];
|
|
128
|
+
}
|
|
129
|
+
color = data + i*stride + j*4;
|
|
130
|
+
color[0] = suma/gauss_sum;
|
|
131
|
+
color[1] = sumr/gauss_sum;
|
|
132
|
+
color[2] = sumg/gauss_sum;
|
|
133
|
+
color[3] = sumb/gauss_sum;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return Qnil;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// cr.horizontal_blur(radius)
|
|
140
|
+
static VALUE method_horizontal_blur(VALUE self, VALUE _radius) {
|
|
141
|
+
int radius = FIX2INT(_radius);
|
|
142
|
+
|
|
143
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
144
|
+
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
145
|
+
int width = cairo_image_surface_get_width(surface);
|
|
146
|
+
int height = cairo_image_surface_get_height(surface);
|
|
147
|
+
int stride = cairo_image_surface_get_stride(surface);
|
|
148
|
+
int length = height*stride;
|
|
149
|
+
|
|
150
|
+
cairo_surface_t *tmp_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
|
|
151
|
+
unsigned char *tmp_data = cairo_image_surface_get_data(tmp_surface);
|
|
152
|
+
|
|
153
|
+
unsigned char *color;
|
|
154
|
+
unsigned char *color2;
|
|
155
|
+
double sumr, sumg, sumb, suma;
|
|
156
|
+
int gauss_w = radius*2 + 1;
|
|
157
|
+
int *mask = triangle[radius];
|
|
158
|
+
int gauss_sum = sums[radius];
|
|
159
|
+
int i, j, k, x, y;
|
|
160
|
+
for (i = 0; i < height; i++) {
|
|
161
|
+
for (j = 0; j < width; j++) {
|
|
162
|
+
color = data + i*stride + j*4;
|
|
163
|
+
if (color < data || color > data + length) continue;
|
|
164
|
+
color2 = tmp_data + i*stride + j*4;
|
|
165
|
+
color2[0] = color[0];
|
|
166
|
+
color2[1] = color[1];
|
|
167
|
+
color2[2] = color[2];
|
|
168
|
+
color2[3] = color[3];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (i = 0; i < height; i++) {
|
|
172
|
+
for (j = 0; j < width; j++) {
|
|
173
|
+
sumr = sumg = sumb = suma = 0;
|
|
174
|
+
for (k = 0; k < gauss_w; k++) {
|
|
175
|
+
int x = j-radius+k;
|
|
176
|
+
if (x > width || x < 0) continue;
|
|
177
|
+
color = tmp_data + i*stride + x*4;
|
|
178
|
+
if (color < tmp_data || color > tmp_data + length) continue;
|
|
179
|
+
suma += color[0]*mask[k];
|
|
180
|
+
sumr += color[1]*mask[k];
|
|
181
|
+
sumg += color[2]*mask[k];
|
|
182
|
+
sumb += color[3]*mask[k];
|
|
183
|
+
}
|
|
184
|
+
color = data + i*stride + j*4;
|
|
185
|
+
color[0] = suma/gauss_sum;
|
|
186
|
+
color[1] = sumr/gauss_sum;
|
|
187
|
+
color[2] = sumg/gauss_sum;
|
|
188
|
+
color[3] = sumb/gauss_sum;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return Qnil;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
int abs(int x) {
|
|
195
|
+
return x < 0 ? -x : x;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// cr.bump_map(height_map, light_x, light_y, light_radius, specular_radius, normal_coefficient=1.0)
|
|
199
|
+
static VALUE method_bump_map(int argc, VALUE *argv, VALUE self) {
|
|
200
|
+
VALUE height_map;
|
|
201
|
+
VALUE _light_x;
|
|
202
|
+
VALUE _light_y;
|
|
203
|
+
VALUE _light_radius;
|
|
204
|
+
VALUE _specular_radius;
|
|
205
|
+
VALUE _normal_coefficient;
|
|
206
|
+
|
|
207
|
+
rb_scan_args(argc, argv, "51", &height_map, &_light_x, &_light_y, &_light_radius, &_specular_radius, &_normal_coefficient);
|
|
208
|
+
if(NIL_P(_normal_coefficient)) _normal_coefficient = DBL2NUM(1.0);
|
|
209
|
+
|
|
210
|
+
int light_x = FIX2INT(rb_Integer(_light_x));
|
|
211
|
+
int light_y = FIX2INT(rb_Integer(_light_y));
|
|
212
|
+
int light_radius = FIX2INT(rb_Integer(_light_radius));
|
|
213
|
+
int specular_radius = FIX2INT(rb_Integer(_specular_radius));
|
|
214
|
+
double normal_coefficient = NUM2DBL(rb_Float(_normal_coefficient));
|
|
215
|
+
|
|
216
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
217
|
+
unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
|
|
218
|
+
int width = cairo_image_surface_get_width(surface);
|
|
219
|
+
int height = cairo_image_surface_get_height(surface);
|
|
220
|
+
int stride = cairo_image_surface_get_stride(surface);
|
|
221
|
+
int length = height * stride;
|
|
222
|
+
|
|
223
|
+
cairo_surface_t *height_surface = RVAL2CRSURFACE(height_map);
|
|
224
|
+
unsigned char *height_data = cairo_image_surface_get_data(height_surface);
|
|
225
|
+
|
|
226
|
+
int x, y;
|
|
227
|
+
for (y = 0; y < height; y++) {
|
|
228
|
+
for (x = 0; x < width; x++) {
|
|
229
|
+
int xnext = y * stride + (x + 1) * 4 - 1;
|
|
230
|
+
int xprev = y * stride + (x - 1) * 4 - 1;
|
|
231
|
+
int xn = (xnext > length || xprev < 0) ? 0 : (height_data[xnext] - height_data[xprev]);
|
|
232
|
+
int ynext = (y + 1) * stride + x * 4 - 1;
|
|
233
|
+
int yprev = (y - 1) * stride + x * 4 - 1;
|
|
234
|
+
int yn = (ynext > length || yprev < 0) ? 0 : (height_data[ynext] - height_data[yprev]);
|
|
235
|
+
int ex = abs(xn*normal_coefficient - x + light_x);
|
|
236
|
+
int ey = abs(yn*normal_coefficient - y + light_y);
|
|
237
|
+
|
|
238
|
+
if (ex > light_radius - 1) ex = light_radius - 1;
|
|
239
|
+
if (ey > light_radius - 1) ey = light_radius - 1;
|
|
240
|
+
|
|
241
|
+
unsigned int color;
|
|
242
|
+
int magnitude = (int) sqrtf((float)ex*ex+ey*ey);
|
|
243
|
+
if (magnitude < specular_radius) {
|
|
244
|
+
int alpha = 255 - magnitude*255/specular_radius;
|
|
245
|
+
if (alpha > 255) alpha = 255;
|
|
246
|
+
if (alpha < 0) alpha = 0;
|
|
247
|
+
color = (alpha << 24) + (alpha << 16) + (alpha << 8) + alpha;
|
|
248
|
+
} else {
|
|
249
|
+
int alpha = (magnitude - specular_radius)*255/(light_radius - specular_radius);
|
|
250
|
+
if (alpha > 255) alpha = 255;
|
|
251
|
+
if (alpha < 0) alpha = 0;
|
|
252
|
+
color = 0xFF000000 & (alpha << 24);
|
|
253
|
+
}
|
|
254
|
+
data[y * width + x] = color;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return Qnil;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// cr.downsample(scale)
|
|
261
|
+
static VALUE method_downsample(VALUE self, VALUE _scale) {
|
|
262
|
+
int scale = FIX2INT(_scale);
|
|
263
|
+
|
|
264
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
265
|
+
unsigned int *data = (unsigned int *) cairo_image_surface_get_data(surface);
|
|
266
|
+
int width = cairo_image_surface_get_width(surface);
|
|
267
|
+
int height = cairo_image_surface_get_height(surface);
|
|
268
|
+
|
|
269
|
+
int w = width / scale;
|
|
270
|
+
int h = height / scale;
|
|
271
|
+
cairo_surface_t *output_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
|
|
272
|
+
unsigned int *output_data = (unsigned int *) cairo_image_surface_get_data(output_surface);
|
|
273
|
+
int denominator = scale * scale;
|
|
274
|
+
|
|
275
|
+
unsigned char * pixel;
|
|
276
|
+
int i, j, k, l;
|
|
277
|
+
int r, g, b, a;
|
|
278
|
+
|
|
279
|
+
for (i=0; i<w+1; i++) {
|
|
280
|
+
for (j=0; j<h+1; j++) {
|
|
281
|
+
r = g = b = a = 0;
|
|
282
|
+
for (k=0; k<scale; k++) {
|
|
283
|
+
for (l=0; l<scale; l++) {
|
|
284
|
+
pixel = (unsigned char *) (data + (j*scale + l)*width + i*scale + k);
|
|
285
|
+
if (pixel < (unsigned char *) data || pixel > (unsigned char *) (data + width * height)) continue;
|
|
286
|
+
r += pixel[0];
|
|
287
|
+
g += pixel[1];
|
|
288
|
+
b += pixel[2];
|
|
289
|
+
a += pixel[3];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
pixel = (unsigned char *) (output_data + j*w + i);
|
|
293
|
+
if (pixel < (unsigned char *) output_data || pixel > (unsigned char *) (output_data + h*w)) continue;
|
|
294
|
+
pixel[0] = r/denominator;
|
|
295
|
+
pixel[1] = g/denominator;
|
|
296
|
+
pixel[2] = b/denominator;
|
|
297
|
+
pixel[3] = a/denominator;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return (CRSURFACE2RVAL(output_surface));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// cr.render_noise
|
|
304
|
+
static VALUE method_render_noise(VALUE self) {
|
|
305
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
306
|
+
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
307
|
+
int height = cairo_image_surface_get_height(surface);
|
|
308
|
+
int stride = cairo_image_surface_get_stride(surface);
|
|
309
|
+
int length = height * stride;
|
|
310
|
+
|
|
311
|
+
unsigned char * pixel;
|
|
312
|
+
unsigned char x;
|
|
313
|
+
for (pixel = data; pixel < data + length; pixel++) {
|
|
314
|
+
pixel[0] = (unsigned char) rand() % 255;
|
|
315
|
+
}
|
|
316
|
+
return Qnil;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// cr.get_values(x, y)
|
|
320
|
+
static VALUE method_get_values(VALUE self, VALUE _x, VALUE _y) {
|
|
321
|
+
int x = FIX2INT(_x);
|
|
322
|
+
int y = FIX2INT(_y);
|
|
323
|
+
|
|
324
|
+
cairo_surface_t *surface = RVAL2CRSURFACE(self);
|
|
325
|
+
unsigned char *data = cairo_image_surface_get_data(surface);
|
|
326
|
+
int width = cairo_image_surface_get_width(surface);
|
|
327
|
+
int height = cairo_image_surface_get_height(surface);
|
|
328
|
+
if (x > width || y > height || x < 0 || y < 0) return Qnil;
|
|
329
|
+
unsigned int *pixel = (unsigned int *) (data + (y*width + x)*4);
|
|
330
|
+
return UINT2NUM(*pixel);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
void Init_native_image_surface_extensions() {
|
|
334
|
+
VALUE cKlass = rb_cObject;
|
|
335
|
+
cKlass = rb_const_get(cKlass,rb_intern("Cairo"));
|
|
336
|
+
cKlass = rb_const_get(cKlass,rb_intern("ImageSurface"));
|
|
337
|
+
rb_define_method(cKlass, "blur", (VALUE(*)(ANYARGS))method_blur, 1);
|
|
338
|
+
rb_define_method(cKlass, "vertical_blur", (VALUE(*)(ANYARGS))method_vertical_blur, 1);
|
|
339
|
+
rb_define_method(cKlass, "horizontal_blur", (VALUE(*)(ANYARGS))method_horizontal_blur, 1);
|
|
340
|
+
rb_define_method(cKlass, "bump_map", (VALUE(*)(ANYARGS))method_bump_map, 5);
|
|
341
|
+
rb_define_method(cKlass, "downsample", (VALUE(*)(ANYARGS))method_downsample, 1);
|
|
342
|
+
rb_define_method(cKlass, "render_noise", (VALUE(*)(ANYARGS))method_render_noise, 0);
|
|
343
|
+
rb_define_method(cKlass, "get_values", (VALUE(*)(ANYARGS))method_get_values, 2);
|
|
344
|
+
}
|
data/lib/acrylic.rb
ADDED
data/lib/border_tools.rb
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'generator'
|
|
2
|
+
class BorderTools < Generator
|
|
3
|
+
attr_accessor :size
|
|
4
|
+
|
|
5
|
+
def self.preview(image=:border, *args)
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.suite(prefix, *args)
|
|
10
|
+
super
|
|
11
|
+
self.new.write_css(prefix)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def draw(image, *args)
|
|
15
|
+
@args = args
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def set_source
|
|
20
|
+
unless @source
|
|
21
|
+
draw_border(*(@args || []))
|
|
22
|
+
@border = @surface
|
|
23
|
+
@source = Cairo::SurfacePattern.new(@border)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def sass(class_name)
|
|
28
|
+
%{
|
|
29
|
+
table.#{class_name}
|
|
30
|
+
border-collapse: collapse
|
|
31
|
+
padding: 0
|
|
32
|
+
margin: 0
|
|
33
|
+
.#{class_name}
|
|
34
|
+
&.tl, &.tr, &.bl, &.br, &.tc, &.bc
|
|
35
|
+
height: #{size}px !important
|
|
36
|
+
padding: 0 !important
|
|
37
|
+
border: 0
|
|
38
|
+
margin: 0
|
|
39
|
+
&.tl, &.bl, &.tr, &.br, &.cl, &.cr
|
|
40
|
+
width: #{size}px !important
|
|
41
|
+
padding: 0 !important
|
|
42
|
+
border: 0
|
|
43
|
+
margin: 0
|
|
44
|
+
&.tl
|
|
45
|
+
background: url(/images/#{class_name}_tl.png)
|
|
46
|
+
&.tr
|
|
47
|
+
background: url(/images/#{class_name}_tr.png)
|
|
48
|
+
&.bl
|
|
49
|
+
background: url(/images/#{class_name}_bl.png)
|
|
50
|
+
&.br
|
|
51
|
+
background: url(/images/#{class_name}_br.png)
|
|
52
|
+
&.cl
|
|
53
|
+
background: url(/images/#{class_name}_cl.png)
|
|
54
|
+
&.tc
|
|
55
|
+
background: url(/images/#{class_name}_tc.png)
|
|
56
|
+
&.cr
|
|
57
|
+
background: url(/images/#{class_name}_cr.png)
|
|
58
|
+
&.bc
|
|
59
|
+
background: url(/images/#{class_name}_bc.png)
|
|
60
|
+
&.content
|
|
61
|
+
background-color: #{background_color.to_css}
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def write_css(name)
|
|
66
|
+
set_source
|
|
67
|
+
path = File.join(File.dirname(__FILE__), "../public/stylesheets/sass/#{name}.sass")
|
|
68
|
+
File.open(path, 'w') {|f| f << sass(name)}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def background_color
|
|
72
|
+
set_source
|
|
73
|
+
@border.get_pixel(@border.width/2, @border.height/2)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.inherited(c)
|
|
77
|
+
c.image :tl do
|
|
78
|
+
slice(size, size, 0, 0)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
c.image :tc do
|
|
82
|
+
slice(1, size, size + 1, 0)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
c.image :tr do
|
|
86
|
+
slice(size, size, @border.width - size, 0)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
c.image :cl do
|
|
90
|
+
slice(size, 1, 0, size + 1)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
c.image :cr do
|
|
94
|
+
slice(size, 1, @border.width - size, size + 1)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
c.image :bl do
|
|
98
|
+
slice(size, size, 0, @border.height - size)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
c.image :bc do
|
|
102
|
+
slice(1, size, size + 1, @border.height - size)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
c.image :br do
|
|
106
|
+
slice(size, size, @border.width - size, @border.height - size)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
c.image :border, :suite => false do
|
|
110
|
+
draw_border
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def slice(sizeX, sizeY, offsetX, offsetY)
|
|
115
|
+
set_source
|
|
116
|
+
dimensions sizeX, sizeY
|
|
117
|
+
cr.set_source(@source)
|
|
118
|
+
cr.source.matrix = Cairo::Matrix.identity.translate(offsetX, offsetY)
|
|
119
|
+
cr.paint
|
|
120
|
+
end
|
|
121
|
+
end
|