rszr 0.4.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,12 @@
1
+ #ifndef RUBY_RSZR_IMAGE_H
2
+ #define RUBY_RSZR_IMAGE_H
3
+
4
+ typedef struct {
5
+ Imlib_Image image;
6
+ } rszr_image_handle;
7
+
8
+ extern VALUE cImage;
9
+
10
+ void Init_rszr_image();
11
+
12
+ #endif
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,11 @@
1
+ #ifndef RUBY_RSZR_H
2
+ #define RUBY_RSZR_H
3
+
4
+ #include "ruby.h"
5
+ #include <Imlib2.h>
6
+ #include <libexif/exif-data.h>
7
+
8
+ extern VALUE mRszr;
9
+ void Init_rszr();
10
+
11
+ #endif
@@ -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