open_image 0.0.1

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.
@@ -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
+ }