rszr 0.4.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +129 -12
- data/Rakefile +6 -0
- data/ext/rszr/errors.c +68 -0
- data/ext/rszr/errors.h +15 -0
- data/ext/rszr/extconf.rb +18 -0
- data/ext/rszr/image.c +482 -0
- data/ext/rszr/image.h +12 -0
- data/ext/rszr/rszr.c +17 -0
- data/ext/rszr/rszr.h +11 -0
- data/lib/rszr/batch_transformation.rb +24 -0
- data/lib/rszr/buffered.rb +25 -0
- data/lib/rszr/identification.rb +60 -0
- data/lib/rszr/image.rb +151 -98
- data/lib/rszr/image_processing.rb +82 -0
- data/lib/rszr/orientation.rb +107 -0
- data/lib/rszr/stream.rb +61 -0
- data/lib/rszr/version.rb +1 -1
- data/lib/rszr.rb +21 -7
- metadata +27 -114
- data/lib/rszr/base.rb +0 -29
- data/lib/rszr/errors.rb +0 -42
- data/lib/rszr/handle.rb +0 -37
- data/lib/rszr/lib.rb +0 -73
- data/lib/rszr/lock.rb +0 -23
data/ext/rszr/image.c
ADDED
@@ -0,0 +1,482 @@
|
|
1
|
+
#ifndef RUBY_RSZR_IMAGE
|
2
|
+
#define RUBY_RSZR_IMAGE
|
3
|
+
|
4
|
+
#include "rszr.h"
|
5
|
+
#include "image.h"
|
6
|
+
#include "errors.h"
|
7
|
+
|
8
|
+
VALUE cImage = Qnil;
|
9
|
+
|
10
|
+
|
11
|
+
static void rszr_free_image(Imlib_Image image)
|
12
|
+
{
|
13
|
+
imlib_context_set_image(image);
|
14
|
+
imlib_free_image();
|
15
|
+
}
|
16
|
+
|
17
|
+
|
18
|
+
static void rszr_image_deallocate(rszr_image_handle * handle)
|
19
|
+
{
|
20
|
+
// fprintf(stderr, "rszr_image_deallocate");
|
21
|
+
if (handle->image) {
|
22
|
+
// fprintf(stderr, ": freeing");
|
23
|
+
rszr_free_image(handle->image);
|
24
|
+
handle->image = NULL;
|
25
|
+
}
|
26
|
+
free(handle);
|
27
|
+
// fprintf(stderr, "\n");
|
28
|
+
}
|
29
|
+
|
30
|
+
static VALUE rszr_image_s_allocate(VALUE klass)
|
31
|
+
{
|
32
|
+
rszr_image_handle * handle = calloc(1, sizeof(rszr_image_handle));
|
33
|
+
return Data_Wrap_Struct(klass, NULL, rszr_image_deallocate, handle);
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
static VALUE rszr_image_initialize(VALUE self, VALUE rb_width, VALUE rb_height)
|
38
|
+
{
|
39
|
+
rszr_image_handle * handle;
|
40
|
+
|
41
|
+
Check_Type(rb_width, T_FIXNUM);
|
42
|
+
Check_Type(rb_height, T_FIXNUM);
|
43
|
+
|
44
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
45
|
+
|
46
|
+
handle->image = imlib_create_image(FIX2INT(rb_width), FIX2INT(rb_height));
|
47
|
+
|
48
|
+
return self;
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
static VALUE rszr_image_s__load(VALUE klass, VALUE rb_path)
|
53
|
+
{
|
54
|
+
rszr_image_handle * handle;
|
55
|
+
Imlib_Image image;
|
56
|
+
char * path;
|
57
|
+
Imlib_Load_Error error;
|
58
|
+
VALUE oImage;
|
59
|
+
|
60
|
+
path = StringValueCStr(rb_path);
|
61
|
+
|
62
|
+
imlib_set_cache_size(0);
|
63
|
+
image = imlib_load_image_without_cache(path);
|
64
|
+
|
65
|
+
if (!image) {
|
66
|
+
image = imlib_load_image_with_error_return(path, &error);
|
67
|
+
|
68
|
+
if (!image) {
|
69
|
+
rszr_raise_load_error(error);
|
70
|
+
return Qnil;
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
imlib_context_set_image(image);
|
75
|
+
imlib_image_set_irrelevant_format(0);
|
76
|
+
|
77
|
+
oImage = rszr_image_s_allocate(cImage);
|
78
|
+
Data_Get_Struct(oImage, rszr_image_handle, handle);
|
79
|
+
handle->image = image;
|
80
|
+
return oImage;
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
static VALUE rszr_image__format_get(VALUE self)
|
85
|
+
{
|
86
|
+
rszr_image_handle * handle;
|
87
|
+
char * format;
|
88
|
+
|
89
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
90
|
+
|
91
|
+
imlib_context_set_image(handle->image);
|
92
|
+
format = imlib_image_format();
|
93
|
+
|
94
|
+
if (format) {
|
95
|
+
return rb_str_new2(format);
|
96
|
+
} else {
|
97
|
+
return Qnil;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
|
102
|
+
static VALUE rszr_image__format_set(VALUE self, VALUE rb_format)
|
103
|
+
{
|
104
|
+
rszr_image_handle * handle;
|
105
|
+
char * format = StringValueCStr(rb_format);
|
106
|
+
|
107
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
108
|
+
|
109
|
+
imlib_context_set_image(handle->image);
|
110
|
+
imlib_image_set_format(format);
|
111
|
+
|
112
|
+
return self;
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
static VALUE rszr_image_width(VALUE self)
|
117
|
+
{
|
118
|
+
rszr_image_handle * handle;
|
119
|
+
int width;
|
120
|
+
|
121
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
122
|
+
|
123
|
+
imlib_context_set_image(handle->image);
|
124
|
+
width = imlib_image_get_width();
|
125
|
+
|
126
|
+
return INT2NUM(width);
|
127
|
+
}
|
128
|
+
|
129
|
+
|
130
|
+
static VALUE rszr_image_height(VALUE self)
|
131
|
+
{
|
132
|
+
rszr_image_handle * handle;
|
133
|
+
int height;
|
134
|
+
|
135
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
136
|
+
|
137
|
+
imlib_context_set_image(handle->image);
|
138
|
+
height = imlib_image_get_height();
|
139
|
+
|
140
|
+
return INT2NUM(height);
|
141
|
+
}
|
142
|
+
|
143
|
+
/*
|
144
|
+
static VALUE rszr_image_get_quality(VALUE self)
|
145
|
+
{
|
146
|
+
rszr_image_handle * handle;
|
147
|
+
int quality;
|
148
|
+
|
149
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
150
|
+
|
151
|
+
imlib_context_set_image(handle->image);
|
152
|
+
quality = imlib_image_get_attached_value("quality");
|
153
|
+
|
154
|
+
if (quality) {
|
155
|
+
return INT2NUM(quality);
|
156
|
+
} else {
|
157
|
+
return Qnil;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
static VALUE rszr_image_set_quality(VALUE self, VALUE rb_quality)
|
162
|
+
{
|
163
|
+
rszr_image_handle * handle;
|
164
|
+
int quality;
|
165
|
+
|
166
|
+
Check_Type(rb_quality, T_FIXNUM);
|
167
|
+
quality = FIX2INT(rb_quality);
|
168
|
+
if (quality <= 0) {
|
169
|
+
rb_raise(rb_eArgError, "quality must be >= 0");
|
170
|
+
return Qnil;
|
171
|
+
}
|
172
|
+
|
173
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
174
|
+
|
175
|
+
imlib_context_set_image(handle->image);
|
176
|
+
imlib_image_attach_data_value("quality", NULL, quality, NULL);
|
177
|
+
|
178
|
+
return INT2NUM(quality);
|
179
|
+
}
|
180
|
+
*/
|
181
|
+
|
182
|
+
static VALUE rszr_image_dup(VALUE self)
|
183
|
+
{
|
184
|
+
rszr_image_handle * handle;
|
185
|
+
rszr_image_handle * cloned_handle;
|
186
|
+
Imlib_Image cloned_image;
|
187
|
+
VALUE oClonedImage;
|
188
|
+
|
189
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
190
|
+
|
191
|
+
imlib_context_set_image(handle->image);
|
192
|
+
cloned_image = imlib_clone_image();
|
193
|
+
|
194
|
+
if (!cloned_image) {
|
195
|
+
rb_raise(eRszrTransformationError, "error cloning image");
|
196
|
+
return Qnil;
|
197
|
+
}
|
198
|
+
|
199
|
+
oClonedImage = rszr_image_s_allocate(cImage);
|
200
|
+
Data_Get_Struct(oClonedImage, rszr_image_handle, cloned_handle);
|
201
|
+
cloned_handle->image = cloned_image;
|
202
|
+
|
203
|
+
return oClonedImage;
|
204
|
+
}
|
205
|
+
|
206
|
+
|
207
|
+
static VALUE rszr_image__turn_bang(VALUE self, VALUE orientation)
|
208
|
+
{
|
209
|
+
rszr_image_handle * handle;
|
210
|
+
|
211
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
212
|
+
|
213
|
+
imlib_context_set_image(handle->image);
|
214
|
+
imlib_image_orientate(NUM2INT(orientation));
|
215
|
+
|
216
|
+
return self;
|
217
|
+
}
|
218
|
+
|
219
|
+
|
220
|
+
static VALUE rszr_image_flop_bang(VALUE self)
|
221
|
+
{
|
222
|
+
rszr_image_handle * handle;
|
223
|
+
|
224
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
225
|
+
|
226
|
+
imlib_context_set_image(handle->image);
|
227
|
+
imlib_image_flip_horizontal();
|
228
|
+
|
229
|
+
return self;
|
230
|
+
}
|
231
|
+
|
232
|
+
|
233
|
+
static VALUE rszr_image_flip_bang(VALUE self)
|
234
|
+
{
|
235
|
+
rszr_image_handle * handle;
|
236
|
+
|
237
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
238
|
+
|
239
|
+
imlib_context_set_image(handle->image);
|
240
|
+
imlib_image_flip_vertical();
|
241
|
+
|
242
|
+
return self;
|
243
|
+
}
|
244
|
+
|
245
|
+
|
246
|
+
static VALUE rszr_image__rotate(VALUE self, VALUE bang, VALUE rb_angle)
|
247
|
+
{
|
248
|
+
rszr_image_handle * handle;
|
249
|
+
rszr_image_handle * rotated_handle;
|
250
|
+
Imlib_Image rotated_image;
|
251
|
+
VALUE oRotatedImage;
|
252
|
+
double angle;
|
253
|
+
|
254
|
+
angle = NUM2DBL(rb_angle);
|
255
|
+
|
256
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
257
|
+
|
258
|
+
imlib_context_set_image(handle->image);
|
259
|
+
rotated_image = imlib_create_rotated_image(angle);
|
260
|
+
|
261
|
+
if (!rotated_image) {
|
262
|
+
rb_raise(eRszrTransformationError, "error rotating image");
|
263
|
+
return Qnil;
|
264
|
+
}
|
265
|
+
|
266
|
+
if (RTEST(bang)) {
|
267
|
+
rszr_free_image(handle->image);
|
268
|
+
handle->image = rotated_image;
|
269
|
+
|
270
|
+
return self;
|
271
|
+
}
|
272
|
+
else {
|
273
|
+
oRotatedImage = rszr_image_s_allocate(cImage);
|
274
|
+
Data_Get_Struct(oRotatedImage, rszr_image_handle, rotated_handle);
|
275
|
+
rotated_handle->image = rotated_image;
|
276
|
+
|
277
|
+
return oRotatedImage;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
|
282
|
+
static VALUE rszr_image_filter_bang(VALUE self, VALUE rb_filter_expr)
|
283
|
+
{
|
284
|
+
rszr_image_handle * handle;
|
285
|
+
char * filter_expr;
|
286
|
+
|
287
|
+
filter_expr = StringValueCStr(rb_filter_expr);
|
288
|
+
|
289
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
290
|
+
|
291
|
+
imlib_context_set_image(handle->image);
|
292
|
+
imlib_apply_filter(filter_expr);
|
293
|
+
|
294
|
+
return self;
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
static VALUE rszr_image__sharpen_bang(VALUE self, VALUE rb_radius)
|
299
|
+
{
|
300
|
+
rszr_image_handle * handle;
|
301
|
+
int radius;
|
302
|
+
|
303
|
+
radius = NUM2INT(rb_radius);
|
304
|
+
|
305
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
306
|
+
|
307
|
+
imlib_context_set_image(handle->image);
|
308
|
+
|
309
|
+
if (radius >= 0) {
|
310
|
+
imlib_image_sharpen(radius);
|
311
|
+
} else {
|
312
|
+
imlib_image_blur(radius);
|
313
|
+
}
|
314
|
+
|
315
|
+
return self;
|
316
|
+
}
|
317
|
+
|
318
|
+
|
319
|
+
static Imlib_Image rszr_create_cropped_scaled_image(const Imlib_Image image, VALUE rb_src_x, VALUE rb_src_y, VALUE rb_src_w, VALUE rb_src_h, VALUE rb_dst_w, VALUE rb_dst_h)
|
320
|
+
{
|
321
|
+
Imlib_Image resized_image;
|
322
|
+
|
323
|
+
int src_x = NUM2INT(rb_src_x);
|
324
|
+
int src_y = NUM2INT(rb_src_y);
|
325
|
+
int src_w = NUM2INT(rb_src_w);
|
326
|
+
int src_h = NUM2INT(rb_src_h);
|
327
|
+
int dst_w = NUM2INT(rb_dst_w);
|
328
|
+
int dst_h = NUM2INT(rb_dst_h);
|
329
|
+
|
330
|
+
// TODO: raise if <= 0
|
331
|
+
|
332
|
+
imlib_context_set_image(image);
|
333
|
+
imlib_context_set_anti_alias(1);
|
334
|
+
resized_image = imlib_create_cropped_scaled_image(src_x, src_y, src_w, src_h, dst_w, dst_h);
|
335
|
+
|
336
|
+
if (!resized_image) {
|
337
|
+
rb_raise(eRszrTransformationError, "error resizing image");
|
338
|
+
return NULL;
|
339
|
+
}
|
340
|
+
|
341
|
+
return resized_image;
|
342
|
+
}
|
343
|
+
|
344
|
+
|
345
|
+
static VALUE rszr_image__resize(VALUE self, VALUE bang, VALUE rb_src_x, VALUE rb_src_y, VALUE rb_src_w, VALUE rb_src_h, VALUE rb_dst_w, VALUE rb_dst_h)
|
346
|
+
{
|
347
|
+
rszr_image_handle * handle;
|
348
|
+
Imlib_Image resized_image;
|
349
|
+
rszr_image_handle * resized_handle;
|
350
|
+
VALUE oResizedImage;
|
351
|
+
|
352
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
353
|
+
|
354
|
+
resized_image = rszr_create_cropped_scaled_image(handle->image, rb_src_x, rb_src_y, rb_src_w, rb_src_h, rb_dst_w, rb_dst_h);
|
355
|
+
if (!resized_image) return Qfalse;
|
356
|
+
|
357
|
+
if (RTEST(bang)) {
|
358
|
+
rszr_free_image(handle->image);
|
359
|
+
handle->image = resized_image;
|
360
|
+
|
361
|
+
return self;
|
362
|
+
}
|
363
|
+
else {
|
364
|
+
oResizedImage = rszr_image_s_allocate(cImage);
|
365
|
+
Data_Get_Struct(oResizedImage, rszr_image_handle, resized_handle);
|
366
|
+
resized_handle->image = resized_image;
|
367
|
+
|
368
|
+
return oResizedImage;
|
369
|
+
}
|
370
|
+
}
|
371
|
+
|
372
|
+
|
373
|
+
static Imlib_Image rszr_create_cropped_image(const Imlib_Image image, VALUE rb_x, VALUE rb_y, VALUE rb_w, VALUE rb_h)
|
374
|
+
{
|
375
|
+
Imlib_Image cropped_image;
|
376
|
+
|
377
|
+
int x = NUM2INT(rb_x);
|
378
|
+
int y = NUM2INT(rb_y);
|
379
|
+
int w = NUM2INT(rb_w);
|
380
|
+
int h = NUM2INT(rb_h);
|
381
|
+
|
382
|
+
imlib_context_set_image(image);
|
383
|
+
cropped_image = imlib_create_cropped_image(x, y, w, h);
|
384
|
+
|
385
|
+
if (!cropped_image) {
|
386
|
+
rb_raise(eRszrTransformationError, "error cropping image");
|
387
|
+
return NULL;
|
388
|
+
}
|
389
|
+
|
390
|
+
return cropped_image;
|
391
|
+
}
|
392
|
+
|
393
|
+
|
394
|
+
static VALUE rszr_image__crop(VALUE self, VALUE bang, VALUE rb_x, VALUE rb_y, VALUE rb_w, VALUE rb_h)
|
395
|
+
{
|
396
|
+
rszr_image_handle * handle;
|
397
|
+
Imlib_Image cropped_image;
|
398
|
+
rszr_image_handle * cropped_handle;
|
399
|
+
VALUE oCroppedImage;
|
400
|
+
|
401
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
402
|
+
|
403
|
+
cropped_image = rszr_create_cropped_image(handle->image, rb_x, rb_y, rb_w, rb_h);
|
404
|
+
if (!cropped_image) return Qfalse;
|
405
|
+
|
406
|
+
if (RTEST(bang)) {
|
407
|
+
rszr_free_image(handle->image);
|
408
|
+
handle->image = cropped_image;
|
409
|
+
|
410
|
+
return self;
|
411
|
+
}
|
412
|
+
else {
|
413
|
+
oCroppedImage = rszr_image_s_allocate(cImage);
|
414
|
+
Data_Get_Struct(oCroppedImage, rszr_image_handle, cropped_handle);
|
415
|
+
cropped_handle->image = cropped_image;
|
416
|
+
|
417
|
+
return oCroppedImage;
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
|
422
|
+
static VALUE rszr_image__save(VALUE self, VALUE rb_path, VALUE rb_format, VALUE rb_quality)
|
423
|
+
{
|
424
|
+
rszr_image_handle * handle;
|
425
|
+
char * path;
|
426
|
+
char * format;
|
427
|
+
int quality;
|
428
|
+
Imlib_Load_Error save_error;
|
429
|
+
|
430
|
+
path = StringValueCStr(rb_path);
|
431
|
+
format = StringValueCStr(rb_format);
|
432
|
+
quality = (NIL_P(rb_quality)) ? 0 : FIX2INT(rb_quality);
|
433
|
+
|
434
|
+
Data_Get_Struct(self, rszr_image_handle, handle);
|
435
|
+
|
436
|
+
imlib_context_set_image(handle->image);
|
437
|
+
imlib_image_set_format(format);
|
438
|
+
if (quality)
|
439
|
+
imlib_image_attach_data_value("quality", NULL, quality, NULL);
|
440
|
+
imlib_save_image_with_error_return(path, &save_error);
|
441
|
+
|
442
|
+
if (save_error) {
|
443
|
+
rszr_raise_save_error(save_error);
|
444
|
+
return Qfalse;
|
445
|
+
}
|
446
|
+
|
447
|
+
return Qtrue;
|
448
|
+
}
|
449
|
+
|
450
|
+
void Init_rszr_image()
|
451
|
+
{
|
452
|
+
cImage = rb_define_class_under(mRszr, "Image", rb_cObject);
|
453
|
+
rb_define_alloc_func(cImage, rszr_image_s_allocate);
|
454
|
+
|
455
|
+
// Class methods
|
456
|
+
rb_define_private_method(rb_singleton_class(cImage), "_load", rszr_image_s__load, 1);
|
457
|
+
|
458
|
+
// Instance methods
|
459
|
+
rb_define_method(cImage, "initialize", rszr_image_initialize, 2);
|
460
|
+
rb_define_method(cImage, "width", rszr_image_width, 0);
|
461
|
+
rb_define_method(cImage, "height", rszr_image_height, 0);
|
462
|
+
rb_define_method(cImage, "dup", rszr_image_dup, 0);
|
463
|
+
rb_define_method(cImage, "filter!", rszr_image_filter_bang, 1);
|
464
|
+
rb_define_method(cImage, "flop!", rszr_image_flop_bang, 0);
|
465
|
+
rb_define_method(cImage, "flip!", rszr_image_flip_bang, 0);
|
466
|
+
|
467
|
+
// rb_define_method(cImage, "quality", rszr_image_get_quality, 0);
|
468
|
+
// rb_define_method(cImage, "quality=", rszr_image_set_quality, 1);
|
469
|
+
|
470
|
+
rb_define_protected_method(cImage, "_format", rszr_image__format_get, 0);
|
471
|
+
rb_define_protected_method(cImage, "_format=", rszr_image__format_set, 1);
|
472
|
+
|
473
|
+
rb_define_private_method(cImage, "_resize", rszr_image__resize, 7);
|
474
|
+
rb_define_private_method(cImage, "_crop", rszr_image__crop, 5);
|
475
|
+
rb_define_private_method(cImage, "_turn!", rszr_image__turn_bang, 1);
|
476
|
+
rb_define_private_method(cImage, "_rotate", rszr_image__rotate, 2);
|
477
|
+
rb_define_private_method(cImage, "_sharpen!", rszr_image__sharpen_bang, 1);
|
478
|
+
|
479
|
+
rb_define_private_method(cImage, "_save", rszr_image__save, 3);
|
480
|
+
}
|
481
|
+
|
482
|
+
#endif
|
data/ext/rszr/image.h
ADDED
data/ext/rszr/rszr.c
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef RUBY_RSZR
|
2
|
+
#define RUBY_RSZR
|
3
|
+
|
4
|
+
#include "rszr.h"
|
5
|
+
#include "image.h"
|
6
|
+
#include "errors.h"
|
7
|
+
|
8
|
+
VALUE mRszr = Qnil;
|
9
|
+
|
10
|
+
void Init_rszr()
|
11
|
+
{
|
12
|
+
mRszr = rb_define_module("Rszr");
|
13
|
+
Init_rszr_errors();
|
14
|
+
Init_rszr_image();
|
15
|
+
}
|
16
|
+
|
17
|
+
#endif
|
data/ext/rszr/rszr.h
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rszr
|
2
|
+
class BatchTransformation
|
3
|
+
attr_reader :transformations, :image
|
4
|
+
|
5
|
+
def initialize(path, **opts)
|
6
|
+
puts "INITIALIZED BATCH for #{path}"
|
7
|
+
@image = path.is_a?(Image) ? path : Image.load(path, **opts)
|
8
|
+
@transformations = []
|
9
|
+
end
|
10
|
+
|
11
|
+
Image::Transformations.instance_methods.grep(/\w\z/) do |method|
|
12
|
+
define_method method do |*args|
|
13
|
+
transformations << [method, args]
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
transformations.each { |method, args| image.public_send("#{method}!", *args) }
|
20
|
+
image
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rszr
|
2
|
+
module Buffered
|
3
|
+
def self.included(base)
|
4
|
+
base.extend Buffered
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def with_tempfile(format, data = nil)
|
10
|
+
raise ArgumentError, 'format is required' unless format
|
11
|
+
result = nil
|
12
|
+
Tempfile.create(['rszr-buffer', ".#{format}"], encoding: 'BINARY') do |file|
|
13
|
+
if data
|
14
|
+
file.binmode
|
15
|
+
file << data
|
16
|
+
file.fsync
|
17
|
+
file.rewind
|
18
|
+
end
|
19
|
+
result = yield(file)
|
20
|
+
end
|
21
|
+
result
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Type reader adapted from fastimage
|
2
|
+
# https://github.com/sdsykes/fastimage/
|
3
|
+
|
4
|
+
module Rszr
|
5
|
+
module Identification
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def identify(data)
|
10
|
+
case data[0, 2]
|
11
|
+
when 'BM'
|
12
|
+
:bmp
|
13
|
+
when 'GI'
|
14
|
+
:gif
|
15
|
+
when 0xff.chr + 0xd8.chr
|
16
|
+
:jpeg
|
17
|
+
when 0x89.chr + 'P'
|
18
|
+
:png
|
19
|
+
when 'II', 'MM'
|
20
|
+
case data[0, 11][8..10] # @stream.peek(11)[8..10]
|
21
|
+
when 'APC', "CR\002"
|
22
|
+
nil # do not recognise CRW or CR2 as tiff
|
23
|
+
else
|
24
|
+
:tiff
|
25
|
+
end
|
26
|
+
when '8B'
|
27
|
+
:psd
|
28
|
+
when "\0\0"
|
29
|
+
case data[0, 3].bytes.last #@stream.peek(3).bytes.to_a.last
|
30
|
+
when 0
|
31
|
+
# http://www.ftyps.com/what.html
|
32
|
+
# HEIC is composed of nested "boxes". Each box has a header composed of
|
33
|
+
# - Size (32 bit integer)
|
34
|
+
# - Box type (4 chars)
|
35
|
+
# - Extended size: only if size === 1, the type field is followed by 64 bit integer of extended size
|
36
|
+
# - Payload: Type-dependent
|
37
|
+
case data[0, 12][4..-1] #@stream.peek(12)[4..-1]
|
38
|
+
when 'ftypheic'
|
39
|
+
:heic
|
40
|
+
when 'ftypmif1'
|
41
|
+
:heif
|
42
|
+
end
|
43
|
+
# ico has either a 1 (for ico format) or 2 (for cursor) at offset 3
|
44
|
+
when 1 then :ico
|
45
|
+
when 2 then :cur
|
46
|
+
end
|
47
|
+
when 'RI'
|
48
|
+
:webp if data[0, 12][8..11] == 'WEBP' #@stream.peek(12)[8..11] == "WEBP"
|
49
|
+
when "<s"
|
50
|
+
:svg if data[0, 4] == '<svg' #@stream.peek(4) == "<svg"
|
51
|
+
when /\s\s|\s<|<[?!]/, 0xef.chr + 0xbb.chr
|
52
|
+
# Peek 10 more chars each time, and if end of file is reached just raise
|
53
|
+
# unknown. We assume the <svg tag cannot be within 10 chars of the end of
|
54
|
+
# the file, and is within the first 250 chars.
|
55
|
+
:svg if (1..25).detect { |n| data[0, 10 * n]&.include?('<svg') }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|