rszr 0.4.0 → 0.8.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/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