open_image 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+
2
+ #ifndef RB_OPEN_IMAGE_COMMON_H
3
+ #define RB_OPEN_IMAGE_COMMON_H 1
4
+
5
+ #define STBI_MALLOC ruby_xmalloc
6
+ #define STBI_REALLOC ruby_xrealloc
7
+ #define STBI_FREE ruby_xfree
8
+
9
+ #define STBIW_MALLOC STBI_MALLOC
10
+ #define STBIW_REALLOC STBI_REALLOC
11
+ #define STBIW_FREE STBI_FREE
12
+
13
+ #define RETURN_WRAP_STRUCT(klass, obj) return Data_Wrap_Struct(klass, NULL, RUBY_DEFAULT_FREE, obj)
14
+ #define STR2SYM(str) ID2SYM(rb_intern(str))
15
+ #define MIN(v1, v2) (v1 > v2 ? v2 : v1)
16
+ #define MAX(v1, v2) (v1 < v2 ? v2 : v1)
17
+
18
+ #include "ruby.h"
19
+ #include "stb_image.h"
20
+ #include "stb_image_write.h"
21
+
22
+ typedef unsigned int uint;
23
+
24
+ typedef struct Image {
25
+ unsigned int width;
26
+ unsigned int height;
27
+ unsigned char *pixels;
28
+ } Image;
29
+
30
+ typedef struct Point {
31
+ int x;
32
+ int y;
33
+ } Point;
34
+
35
+ typedef struct Size {
36
+ int width;
37
+ int height;
38
+ } Size;
39
+
40
+ typedef struct Rect {
41
+ int x;
42
+ int y;
43
+ int width;
44
+ int height;
45
+ } Rect;
46
+
47
+ typedef struct Color {
48
+ unsigned char r;
49
+ unsigned char g;
50
+ unsigned char b;
51
+ unsigned char a;
52
+ } Color;
53
+
54
+ extern VALUE rb_mOpenImage;
55
+ extern VALUE rb_eOpenImageError;
56
+ extern VALUE rb_cOpenImage;
57
+ extern VALUE rb_cOpenImageColor;
58
+ extern VALUE rb_cOpenImagePoint;
59
+ extern VALUE rb_cOpenImageSize;
60
+ extern VALUE rb_cOpenImageRect;
61
+
62
+ #endif /* RB_OPEN_IMAGE_COMMON_H */
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("open_image/open_image")
@@ -0,0 +1,398 @@
1
+
2
+ #include "image.h"
3
+
4
+ #define IMAGE() \
5
+ Image *image; \
6
+ Data_Get_Struct(self, Image, image);
7
+
8
+ #define JPEG_QUALITY 90
9
+ #define COLOR_SIZE 4 /* For possible future expandment */
10
+ #define COLOR_COMP 4 /* Number of color components */
11
+
12
+ VALUE rb_cOpenImage;
13
+ VALUE rb_cOpenImagePointer;
14
+
15
+ void Init_open_image_image(VALUE module) {
16
+ rb_cOpenImage = rb_define_class_under(module, "Image", rb_cObject);
17
+
18
+ rb_define_alloc_func(rb_cOpenImage, open_image_alloc);
19
+ rb_define_method(rb_cOpenImage, "initialize", open_image_initialize, -1);
20
+ rb_define_method(rb_cOpenImage, "dispose", open_image_dispose, 0);
21
+ rb_define_method(rb_cOpenImage, "disposed?", open_image_disposed_p, 0);
22
+
23
+ rb_define_method(rb_cOpenImage, "width", open_image_width, 0);
24
+ rb_define_method(rb_cOpenImage, "height", open_image_height, 0);
25
+ rb_define_method(rb_cOpenImage, "pixels", open_image_pixels, 0);
26
+ rb_define_alias(rb_cOpenImage, "rows", "height");
27
+ rb_define_alias(rb_cOpenImage, "columns", "width");
28
+ rb_define_alias(rb_cOpenImage, "to_blob", "pixels");
29
+ rb_define_method(rb_cOpenImage, "dup", open_image_dup, 0);
30
+
31
+ rb_define_method(rb_cOpenImage, "ptr", open_image_ptr, 0);
32
+ rb_define_method(rb_cOpenImage, "size", open_image_size, 0);
33
+ rb_define_method(rb_cOpenImage, "rect", open_image_rect, 0);
34
+ rb_define_method(rb_cOpenImage, "to_s", open_image_to_s, 0);
35
+ rb_define_alias(rb_cOpenImage, "to_str", "to_s");
36
+
37
+ rb_define_method(rb_cOpenImage, "save_png", open_image_save_png, 1);
38
+ rb_define_method(rb_cOpenImage, "save_jpg", open_image_save_jpg, -1);
39
+ rb_define_method(rb_cOpenImage, "save_bmp", open_image_save_bmp, 1);
40
+ rb_define_method(rb_cOpenImage, "save_tga", open_image_save_tga, 1);
41
+
42
+ rb_define_method(rb_cOpenImage, "get_pixel", open_image_get_pixel, -1);
43
+ rb_define_method(rb_cOpenImage, "set_pixel", open_image_set_pixel, -1);
44
+ rb_define_method(rb_cOpenImage, "fill_rect", open_image_fill_rect, -1);
45
+ rb_define_method(rb_cOpenImage, "subimage", open_image_subimage, -1);
46
+
47
+ rb_define_method(rb_cOpenImage, "split", open_image_split, 2);
48
+ }
49
+
50
+ static inline void open_image_free(void *data) {
51
+ Image *image = (Image *)data;
52
+ xfree(image->pixels);
53
+ xfree(image);
54
+ image->pixels = NULL;
55
+ }
56
+
57
+ VALUE open_image_dispose(VALUE self) {
58
+ open_image_free(RDATA(self)->data);
59
+ }
60
+
61
+ VALUE open_image_disposed_p(VALUE self) {
62
+ IMAGE();
63
+ return image->pixels ? Qfalse : Qtrue;
64
+ }
65
+
66
+ VALUE open_image_alloc(VALUE klass) {
67
+ Image *image = ALLOC(Image);
68
+ memset(image, 0, sizeof(Image));
69
+ return Data_Wrap_Struct(klass, NULL, open_image_free, image);
70
+ }
71
+
72
+ VALUE open_image_initialize(int argc, VALUE *argv, VALUE self) {
73
+ IMAGE();
74
+
75
+ VALUE arg1, arg2, options;
76
+ argc = rb_scan_args(argc, argv, "11:", &arg1, &arg2, &options);
77
+
78
+ int flip = !NIL_P(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("flip"))));
79
+
80
+ if (argc == 1) // From File
81
+ {
82
+ Check_Type(arg1, T_STRING);
83
+ const char *filename = StringValueCStr(arg1);
84
+ if (flip)
85
+ stbi_set_flip_vertically_on_load(TRUE);
86
+
87
+ int n;
88
+ image->pixels = (unsigned char *)stbi_load(filename, &image->width, &image->height, &n, COLOR_COMP);
89
+
90
+ if (flip)
91
+ stbi_set_flip_vertically_on_load(FALSE);
92
+ } else // From Dimensions
93
+ {
94
+ uint w = NUM2UINT(arg1);
95
+ uint h = NUM2UINT(arg2);
96
+ size_t size = w * h * COLOR_SIZE;
97
+
98
+ image->width = w;
99
+ image->height = h;
100
+ image->pixels = xmalloc(size);
101
+
102
+ VALUE c = Qnil;
103
+ if (!NIL_P(options))
104
+ c = rb_hash_aref(options, ID2SYM(rb_intern("color")));
105
+
106
+ if (NIL_P(c))
107
+ memset(image->pixels, 0, size);
108
+ else {
109
+ Color *src;
110
+ Data_Get_Struct(c, Color, src);
111
+
112
+ unsigned char *dst = (unsigned char *)image->pixels;
113
+ size_t sz = sizeof(Color);
114
+ for (int i = 0; i < size; i += sz)
115
+ memcpy(dst + i, src, sz);
116
+ }
117
+ }
118
+
119
+ if (rb_block_given_p()) {
120
+ rb_yield(self);
121
+ open_image_free(image);
122
+ }
123
+
124
+ return Qnil;
125
+ }
126
+
127
+ VALUE open_image_width(VALUE self) {
128
+ IMAGE();
129
+ return UINT2NUM(image->width);
130
+ }
131
+
132
+ VALUE open_image_height(VALUE self) {
133
+ IMAGE();
134
+ return UINT2NUM(image->height);
135
+ }
136
+
137
+ VALUE open_image_pixels(VALUE self) {
138
+ IMAGE();
139
+ long size = (long)(image->width * image->height * COLOR_SIZE);
140
+ return rb_str_new(image->pixels, size);
141
+ }
142
+
143
+ VALUE open_image_ptr(VALUE self) {
144
+ if (!rb_cOpenImagePointer) {
145
+ rb_require("fiddle");
146
+ VALUE fiddle = rb_const_get(rb_cObject, rb_intern("Fiddle"));
147
+ rb_cOpenImagePointer = rb_const_get(fiddle, rb_intern("Pointer"));
148
+ }
149
+
150
+ IMAGE();
151
+ VALUE *args = xmalloc(sizeof(VALUE) * 2);
152
+ args[0] = LL2NUM((size_t)&image->pixels);
153
+ args[1] = UINT2NUM(image->width * image->height * 4);
154
+ VALUE pointer = rb_obj_alloc(rb_cOpenImagePointer);
155
+ rb_obj_call_init(pointer, 2, args);
156
+ xfree(args);
157
+ return pointer;
158
+ }
159
+
160
+ VALUE open_image_save_png(VALUE self, VALUE path) {
161
+ IMAGE();
162
+ const char *filename = StringValueCStr(path);
163
+ int stride = image->width * COLOR_SIZE;
164
+ int result = stbi_write_png(filename, image->width, image->height, COLOR_COMP, image->pixels, stride);
165
+ return result ? Qtrue : Qfalse;
166
+ }
167
+
168
+ VALUE open_image_save_jpg(int argc, VALUE *argv, VALUE self) {
169
+ IMAGE();
170
+ VALUE path, quality;
171
+ rb_scan_args(argc, argv, "11", &path, &quality);
172
+
173
+ int q = NIL_P(quality) ? JPEG_QUALITY : NUM2INT(quality);
174
+ const char *filename = StringValueCStr(path);
175
+
176
+ int result = stbi_write_jpg(filename, image->width, image->height, COLOR_COMP, image->pixels, q);
177
+ return result ? Qtrue : Qfalse;
178
+ }
179
+
180
+ VALUE open_image_save_tga(VALUE self, VALUE path) {
181
+ IMAGE();
182
+ const char *filename = StringValueCStr(path);
183
+ int result = stbi_write_tga(filename, image->width, image->height, COLOR_COMP, image->pixels);
184
+ return result ? Qtrue : Qfalse;
185
+ }
186
+
187
+ VALUE open_image_save_bmp(VALUE self, VALUE path) {
188
+ IMAGE();
189
+ const char *filename = StringValueCStr(path);
190
+ int result = stbi_write_bmp(filename, image->width, image->height, COLOR_COMP, image->pixels);
191
+ return result ? Qtrue : Qfalse;
192
+ }
193
+
194
+ VALUE open_image_get_pixel(int argc, VALUE *argv, VALUE self) {
195
+ IMAGE();
196
+ Color *color = ALLOC(Color);
197
+ int x, y;
198
+ if (argc == 1) {
199
+ Point *point;
200
+ Data_Get_Struct(argv[0], Point, point);
201
+ x = point->x;
202
+ y = point->y;
203
+ } else if (argc == 2) {
204
+ x = NUM2INT(argv[0]);
205
+ y = NUM2INT(argv[1]);
206
+ } else
207
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 2)", argc);
208
+
209
+ if (x < 0 || x >= image->width)
210
+ rb_raise(rb_eRangeError, "x coordinate outside of image bounds (given %d, expected 0...%u)", x, image->width);
211
+ if (y < 0 || y >= image->height)
212
+ rb_raise(rb_eRangeError, "y coordinate outside of image bounds (given %d, expected 0...%u)", y, image->height);
213
+
214
+ int offset = (x + (y * image->width)) * COLOR_SIZE;
215
+ memcpy(color, *(&image->pixels) + offset, COLOR_SIZE);
216
+ RETURN_WRAP_STRUCT(rb_cOpenImageColor, color);
217
+ }
218
+
219
+ VALUE open_image_set_pixel(int argc, VALUE *argv, VALUE self) {
220
+ IMAGE();
221
+ int x, y;
222
+ Color *color;
223
+ if (argc == 2) {
224
+ Point *point;
225
+ Data_Get_Struct(argv[0], Point, point);
226
+ x = point->x;
227
+ y = point->y;
228
+ Data_Get_Struct(argv[1], Color, color);
229
+ } else if (argc == 3) {
230
+ x = NUM2INT(argv[0]);
231
+ y = NUM2INT(argv[1]);
232
+ Data_Get_Struct(argv[2], Color, color);
233
+ } else
234
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 3)", argc);
235
+
236
+ if (x < 0 || x >= image->width)
237
+ rb_raise(rb_eRangeError, "x coordinate outside of image bounds (given %d, expected 0...%u)", x, image->width);
238
+ if (y < 0 || y >= image->height)
239
+ rb_raise(rb_eRangeError, "y coordinate outside of image bounds (given %d, expected 0...%u)", y, image->height);
240
+
241
+ int offset = (x + (y * image->width)) * COLOR_SIZE;
242
+ memcpy(*(&image->pixels) + offset, color, COLOR_SIZE);
243
+
244
+ return self;
245
+ }
246
+
247
+ VALUE open_image_fill_rect(int argc, VALUE *argv, VALUE self) {
248
+ IMAGE();
249
+ int t, l, r, b;
250
+ Color *color;
251
+ if (argc == 2) {
252
+ Rect *rect;
253
+ Data_Get_Struct(argv[0], Rect, rect);
254
+ l = MAX(rect->x, 0);
255
+ t = MAX(rect->y, 0);
256
+ r = MIN(l + NUM2INT(rect->width), image->width - 1);
257
+ b = MIN(t + NUM2INT(rect->height), image->height - 1);
258
+ Data_Get_Struct(argv[1], Color, color);
259
+ } else if (argc == 5) {
260
+ l = MAX(NUM2INT(argv[0]), 0);
261
+ t = MAX(NUM2INT(argv[1]), 0);
262
+ r = MIN(NUM2INT(argv[2]) + l, image->width - 1);
263
+ b = MIN(NUM2INT(argv[3]) + t, image->height - 1);
264
+ Data_Get_Struct(argv[4], Color, color);
265
+ } else
266
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 2, 5)", argc);
267
+
268
+ if (l >= r || t >= b)
269
+ rb_raise(rb_eOpenImageError, "invalid rectangle specified (%d, %d, %d, %d)", l, t, r - l, b - t);
270
+
271
+ int w = (r - l) * COLOR_SIZE;
272
+ for (int y = t; y < b; y++) {
273
+ int offset = (l + (y * image->width)) * COLOR_SIZE;
274
+ for (int i = 0; i < w; i += COLOR_SIZE) {
275
+ memcpy(*(&image->pixels) + offset + i, color, COLOR_SIZE);
276
+ }
277
+ }
278
+ return self;
279
+ }
280
+
281
+ VALUE open_image_subimage(int argc, VALUE *argv, VALUE self) {
282
+ IMAGE();
283
+ int t, l, r, b;
284
+ if (argc == 1) {
285
+ Rect *rect;
286
+ Data_Get_Struct(argv[0], Rect, rect);
287
+ l = MAX(rect->x, 0);
288
+ t = MAX(rect->y, 0);
289
+ r = MIN(l + NUM2INT(rect->width), image->width - 1);
290
+ b = MIN(t + NUM2INT(rect->height), image->height - 1);
291
+ } else if (argc == 4) {
292
+ l = MAX(NUM2INT(argv[0]), 0);
293
+ t = MAX(NUM2INT(argv[1]), 0);
294
+ r = MIN(NUM2INT(argv[2]) + l, image->width - 1);
295
+ b = MIN(NUM2INT(argv[3]) + t, image->height - 1);
296
+ } else
297
+ rb_raise(rb_eArgError, "wrong number of arguments (given %d, expected 1, 4)", argc);
298
+
299
+ if (l >= r || t >= b)
300
+ rb_raise(rb_eOpenImageError, "invalid rectangle specified (%d, %d, %d, %d)", l, t, r - l, b - t);
301
+
302
+ unsigned char *dst = xmalloc((r - l) * (b - t) * COLOR_SIZE);
303
+ unsigned char *src = *(&image->pixels);
304
+
305
+ size_t w = (r - l) * COLOR_SIZE;
306
+ int i = 0;
307
+ for (int y = t; y < b; y++, i++) {
308
+ int d = i * w;
309
+ int s = (l + (y * image->width)) * COLOR_SIZE;
310
+ memcpy(dst + d, src + s, w);
311
+ }
312
+ Image *sub = ALLOC(Image);
313
+ sub->width = r - l;
314
+ sub->height = b - t;
315
+ sub->pixels = dst;
316
+ return Data_Wrap_Struct(CLASS_OF(self), NULL, open_image_free, sub);
317
+ }
318
+
319
+ VALUE open_image_split(VALUE self, VALUE rows, VALUE columns) {
320
+ int r = NUM2INT(rows);
321
+ int c = NUM2INT(columns);
322
+
323
+ if (r < 1)
324
+ rb_raise(rb_eOpenImageError, "row count must be greater than 0 (given %d)", r);
325
+ if (c < 1)
326
+ rb_raise(rb_eOpenImageError, "column count must be greater than 0 (given %d)", c);
327
+
328
+ if (r == 1 && c == 1)
329
+ return rb_Array(self);
330
+
331
+ IMAGE();
332
+ if (image->width % c != 0)
333
+ rb_raise(rb_eOpenImageError, "specified number of columns (%d) must be evenly divisible by image width (%u)", c, image->width);
334
+
335
+ if (image->height % r != 0)
336
+ rb_raise(rb_eOpenImageError, "specified number of rows (%d) must be evenly divisible by image height (%u)", r, image->height);
337
+
338
+ uint w = image->width / c;
339
+ uint h = image->height / r;
340
+
341
+ int d, s, tx, ty, count = r * c;
342
+ VALUE ary = rb_ary_new_capa(count);
343
+
344
+ size_t row_width = w * COLOR_SIZE;
345
+ VALUE klass = CLASS_OF(self);
346
+ unsigned char *src = *(&image->pixels);
347
+ for (int i = 0; i < count; i++) {
348
+ tx = i % c;
349
+ ty = i / c;
350
+ unsigned char *dst = xmalloc(w * h * COLOR_SIZE);
351
+ for (int y = 0; y < h; y++) {
352
+ d = y * row_width;
353
+ s = ((y * image->width) + (tx * w) + ((ty * h) * image->width)) * COLOR_SIZE;
354
+ memcpy(dst + d, src + s, row_width);
355
+ }
356
+ Image *sub = ALLOC(Image);
357
+ sub->width = w;
358
+ sub->height = h;
359
+ sub->pixels = dst;
360
+ rb_ary_store(ary, i, Data_Wrap_Struct(klass, NULL, open_image_free, sub));
361
+ }
362
+ return ary;
363
+ }
364
+
365
+ VALUE open_image_size(VALUE self) {
366
+ IMAGE();
367
+ Size *size = ALLOC(Size);
368
+ size->width = image->width;
369
+ size->height = image->height;
370
+ RETURN_WRAP_STRUCT(rb_cOpenImageSize, size);
371
+ }
372
+
373
+ VALUE open_image_rect(VALUE self) {
374
+ IMAGE();
375
+ Rect *rect = ALLOC(Rect);
376
+ rect->x = 0;
377
+ rect->y = 0;
378
+ rect->width = image->width;
379
+ rect->height = image->height;
380
+ RETURN_WRAP_STRUCT(rb_cOpenImageRect, rect);
381
+ }
382
+
383
+ VALUE open_image_to_s(VALUE self) {
384
+ IMAGE();
385
+ return rb_sprintf("<Image: width:%u, height:%u>", image->width, image->height);
386
+ }
387
+
388
+ VALUE open_image_dup(VALUE self) {
389
+ IMAGE();
390
+ Image *clone = ALLOC(Image);
391
+ memcpy(clone, image, sizeof(uint) * 2);
392
+
393
+ size_t size = clone->width * clone->height * COLOR_SIZE;
394
+ clone->pixels = xmalloc(size);
395
+ memcpy(*(&clone->pixels), *(&image->pixels), size);
396
+
397
+ return Data_Wrap_Struct(CLASS_OF(self), NULL, open_image_free, clone);
398
+ }