async-ruby-vips 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile.lock +63 -0
- data/README.md +101 -0
- data/async-ruby-vips.gemspec +74 -0
- data/ext/LICENSE +20 -0
- data/ext/async_vips.c +73 -0
- data/ext/async_vips.h +11 -0
- data/ext/callback.c +119 -0
- data/ext/callback.h +9 -0
- data/ext/details.c +54 -0
- data/ext/details.h +15 -0
- data/ext/extconf.rb +18 -0
- data/ext/image.c +66 -0
- data/ext/image.h +13 -0
- data/ext/info.c +42 -0
- data/ext/info.h +8 -0
- data/ext/transform.c +396 -0
- data/ext/transform.h +11 -0
- data/ext/transform_data.c +74 -0
- data/ext/transform_data.h +34 -0
- data/ext/transform_data_fwd.h +6 -0
- data/ext/writer.c +96 -0
- data/ext/writer.h +7 -0
- data/lib/async_vips.rb +5 -0
- data/lib/async_vips/version.rb +3 -0
- metadata +125 -0
data/ext/callback.h
ADDED
data/ext/details.c
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#include "details.h"
|
2
|
+
|
3
|
+
int image_scale_none = 0x00;
|
4
|
+
int image_scale_stretch = 0x01;
|
5
|
+
int image_scale_fit = 0x02;
|
6
|
+
int image_scale_no_scale_up = 0x04;
|
7
|
+
int image_scale_detect_proportions = 0x08; // detect if the picture width & height are need to be swapped
|
8
|
+
int image_scale_fit_no_scale_up = 0x06; // = (fit | no scale_up)
|
9
|
+
|
10
|
+
/* Get the factors for scale transformation */
|
11
|
+
void av_get_scale_transform2(int original_width, int original_height, int desired_width, int desired_height, int scale_mode, double* factor_x, double* factor_y)
|
12
|
+
{
|
13
|
+
if(scale_mode & image_scale_none) // NONE
|
14
|
+
{
|
15
|
+
*factor_x = *factor_y = 1.0;
|
16
|
+
}
|
17
|
+
else if(scale_mode & image_scale_stretch) // STRETCH
|
18
|
+
{
|
19
|
+
*factor_x = (double) (original_width) / (double) (desired_width);
|
20
|
+
*factor_y = (double) (original_height) / (double) (desired_height);
|
21
|
+
}
|
22
|
+
else if(scale_mode & image_scale_fit) // FIT
|
23
|
+
{
|
24
|
+
if(scale_mode & image_scale_detect_proportions)
|
25
|
+
{
|
26
|
+
double p1, p2;
|
27
|
+
|
28
|
+
p1 = (double) (desired_width) / (double) (desired_height);
|
29
|
+
p2 = (double) (original_width) / (double) (original_height);
|
30
|
+
|
31
|
+
if((p1 > 1.0 && p2 < 1.0) || (p1 < 1.0 && p2 > 1.0))
|
32
|
+
{
|
33
|
+
int temp = desired_width;
|
34
|
+
desired_width = desired_height;
|
35
|
+
desired_height = temp;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
double k1, k2, k;
|
40
|
+
|
41
|
+
k1 = (double) (original_width) / (double) (desired_width);
|
42
|
+
k2 = (double) (original_height) / (double) (desired_height);
|
43
|
+
|
44
|
+
k = (k1 > k2 ? k1 : k2);
|
45
|
+
|
46
|
+
if(scale_mode & image_scale_no_scale_up)
|
47
|
+
{
|
48
|
+
if(k < 1.0)
|
49
|
+
k = 1.0; // do not scale up small images at all.
|
50
|
+
}
|
51
|
+
|
52
|
+
*factor_x = *factor_y = k;
|
53
|
+
}
|
54
|
+
}
|
data/ext/details.h
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#ifndef ASYNC_VIPS_IMAGE_H
|
2
|
+
#define ASYNC_VIPS_IMAGE_H
|
3
|
+
|
4
|
+
extern int image_scale_none;
|
5
|
+
extern int image_scale_stretch;
|
6
|
+
extern int image_scale_fit;
|
7
|
+
extern int image_scale_no_scale_up;
|
8
|
+
extern int image_scale_detect_proportions;
|
9
|
+
extern int image_scale_fit_no_scale_up;
|
10
|
+
|
11
|
+
|
12
|
+
void av_get_scale_transform2(int original_width, int original_height, int desired_width, int desired_height, int scale_mode, double* factor_x, double* factor_y);
|
13
|
+
|
14
|
+
|
15
|
+
#endif
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
2
|
+
|
3
|
+
require "mkmf"
|
4
|
+
|
5
|
+
File::unlink("Makefile") if (File::exist?("Makefile"))
|
6
|
+
|
7
|
+
if not pkg_config("vips")
|
8
|
+
VIPS_VERSIONS = %w[7.29 7.28 7.27 7.26 7.24]
|
9
|
+
|
10
|
+
if not VIPS_VERSIONS.detect {|x| pkg_config("vips-#{x}") }
|
11
|
+
raise("no pkg_config for any of following libvips versions: #{VIPS_VERSIONS.join(', ')}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
have_header('vips/vips.h')
|
16
|
+
have_header('libexif/exif-data.h')
|
17
|
+
|
18
|
+
create_makefile('async_vips_ext')
|
data/ext/image.c
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#include "image.h"
|
2
|
+
#include <sys/types.h>
|
3
|
+
#include <sys/stat.h>
|
4
|
+
|
5
|
+
|
6
|
+
VALUE cImage;
|
7
|
+
|
8
|
+
/* Get the source parameter */
|
9
|
+
static VALUE av_image_src(VALUE self)
|
10
|
+
{
|
11
|
+
return rb_iv_get(self, "@src");
|
12
|
+
}
|
13
|
+
|
14
|
+
/* Get the destination parameter */
|
15
|
+
static VALUE av_image_dst(VALUE self)
|
16
|
+
{
|
17
|
+
return rb_iv_get(self, "@dst");
|
18
|
+
}
|
19
|
+
|
20
|
+
/* Get the error parameter */
|
21
|
+
static VALUE av_image_error(VALUE self)
|
22
|
+
{
|
23
|
+
return rb_iv_get(self, "@error");
|
24
|
+
}
|
25
|
+
|
26
|
+
/* Get the image width */
|
27
|
+
static VALUE av_image_width(VALUE self)
|
28
|
+
{
|
29
|
+
return rb_iv_get(self, "@width");
|
30
|
+
}
|
31
|
+
|
32
|
+
/* Get the image height */
|
33
|
+
static VALUE av_image_height(VALUE self)
|
34
|
+
{
|
35
|
+
return rb_iv_get(self, "@height");
|
36
|
+
}
|
37
|
+
|
38
|
+
/* Get the size of the dst-image file */
|
39
|
+
static VALUE av_image_size(VALUE self)
|
40
|
+
{
|
41
|
+
return rb_iv_get(self, "@size");
|
42
|
+
}
|
43
|
+
|
44
|
+
/* Initialize the object, called before the callback is invoked */
|
45
|
+
void av_image_init(VALUE self, const transform_data_t* tdata)
|
46
|
+
{
|
47
|
+
rb_iv_set(self, "@src", (tdata->src_path ? rb_str_new2(tdata->src_path) : Qnil));
|
48
|
+
rb_iv_set(self, "@dst", (tdata->dst_path ? rb_str_new2(tdata->dst_path) : Qnil));
|
49
|
+
rb_iv_set(self, "@error", (tdata->err_str ? rb_str_new2(tdata->err_str) : Qnil));
|
50
|
+
rb_iv_set(self, "@width", INT2FIX(tdata->final_width));
|
51
|
+
rb_iv_set(self, "@height", INT2FIX(tdata->final_height));
|
52
|
+
rb_iv_set(self, "@size", INT2FIX(tdata->final_size));
|
53
|
+
}
|
54
|
+
|
55
|
+
|
56
|
+
void init_async_vips_image()
|
57
|
+
{
|
58
|
+
cImage = rb_define_class_under(mAsyncVips, "Image", rb_cObject);
|
59
|
+
|
60
|
+
rb_define_method(cImage, "src", av_image_src, 0);
|
61
|
+
rb_define_method(cImage, "dst", av_image_dst, 0);
|
62
|
+
rb_define_method(cImage, "error", av_image_error, 0);
|
63
|
+
rb_define_method(cImage, "width", av_image_width, 0);
|
64
|
+
rb_define_method(cImage, "height", av_image_height, 0);
|
65
|
+
rb_define_method(cImage, "size", av_image_size, 0);
|
66
|
+
}
|
data/ext/image.h
ADDED
data/ext/info.c
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#include "info.h"
|
2
|
+
#include "transform.h"
|
3
|
+
#include "writer.h"
|
4
|
+
#include <sys/types.h>
|
5
|
+
#include <sys/stat.h>
|
6
|
+
|
7
|
+
ID av_i_id_load;
|
8
|
+
|
9
|
+
/* Returns image information: width, height, file size */
|
10
|
+
static VALUE av_info(int argc, VALUE *argv, VALUE self)
|
11
|
+
{
|
12
|
+
rb_need_block();
|
13
|
+
VALUE proc = rb_block_proc();
|
14
|
+
|
15
|
+
VALUE rest;
|
16
|
+
rb_scan_args(argc, argv, "*", &rest);
|
17
|
+
|
18
|
+
VALUE params = rb_ary_pop(rest);
|
19
|
+
VALUE tmp = rb_check_hash_type(params);
|
20
|
+
if (NIL_P(tmp))
|
21
|
+
rb_raise(rb_eArgError, "No info parameters specified");
|
22
|
+
|
23
|
+
// Parse options
|
24
|
+
VALUE load = rb_hash_aref(params, ID2SYM(av_i_id_load));
|
25
|
+
if(NIL_P(load))
|
26
|
+
rb_raise(rb_eArgError, "No image source specified: info(:load => 'image.jpg')");
|
27
|
+
|
28
|
+
transform_data_t* tdata = av_make_transform_data_src(StringValuePtr(load));
|
29
|
+
tdata->proc = proc;
|
30
|
+
|
31
|
+
rb_gc_register_address(&tdata->proc);
|
32
|
+
|
33
|
+
av_enqueue_task(av_build_image_thread_func, tdata);
|
34
|
+
|
35
|
+
return self;
|
36
|
+
}
|
37
|
+
|
38
|
+
void init_async_vips_info()
|
39
|
+
{
|
40
|
+
rb_define_singleton_method(mAsyncVips, "info", av_info, -1);
|
41
|
+
av_i_id_load = rb_intern("load");
|
42
|
+
}
|
data/ext/info.h
ADDED
data/ext/transform.c
ADDED
@@ -0,0 +1,396 @@
|
|
1
|
+
#include "transform.h"
|
2
|
+
#include "callback.h"
|
3
|
+
#include "details.h"
|
4
|
+
#include <pthread.h>
|
5
|
+
#include <libexif/exif-data.h>
|
6
|
+
#include <sys/stat.h>
|
7
|
+
|
8
|
+
|
9
|
+
ID av_t_id_load;
|
10
|
+
ID av_t_id_save;
|
11
|
+
ID av_t_id_scale_x;
|
12
|
+
ID av_t_id_scale_y;
|
13
|
+
ID av_t_id_natural_orientation;
|
14
|
+
|
15
|
+
|
16
|
+
/* Get the size of a file */
|
17
|
+
static void av_get_image_file_size(const char* file_path, long long* file_size)
|
18
|
+
{
|
19
|
+
long long sz = 0;
|
20
|
+
if(file_path)
|
21
|
+
{
|
22
|
+
int err;
|
23
|
+
struct stat st;
|
24
|
+
memset(&st, 0, sizeof(st));
|
25
|
+
err = stat(file_path, &st);
|
26
|
+
if(!err)
|
27
|
+
{
|
28
|
+
sz = st.st_size;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
*file_size = sz;
|
33
|
+
}
|
34
|
+
|
35
|
+
/*
|
36
|
+
Get image orientation from EXIF
|
37
|
+
|
38
|
+
0th Row 0th Column
|
39
|
+
1 top left side
|
40
|
+
2 top right side
|
41
|
+
3 bottom right side
|
42
|
+
4 bottom left side
|
43
|
+
5 left side top
|
44
|
+
6 right side top
|
45
|
+
7 right side bottom
|
46
|
+
8 left side bottom
|
47
|
+
*/
|
48
|
+
static int av_get_orientation(VipsImage* image)
|
49
|
+
{
|
50
|
+
int orientation = 0;
|
51
|
+
|
52
|
+
GType exif_type = vips_image_get_typeof(image, VIPS_META_EXIF_NAME);
|
53
|
+
if(exif_type != 0)
|
54
|
+
{
|
55
|
+
unsigned char *data;
|
56
|
+
size_t data_length;
|
57
|
+
if(!vips_image_get_blob(image, VIPS_META_EXIF_NAME, (void *)&data, &data_length))
|
58
|
+
{
|
59
|
+
ExifData *ed;
|
60
|
+
ed = exif_data_new_from_data(data, data_length);
|
61
|
+
if(ed != NULL)
|
62
|
+
{
|
63
|
+
ExifByteOrder bo = exif_data_get_byte_order(ed);
|
64
|
+
ExifEntry *ee = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
|
65
|
+
if(ee)
|
66
|
+
{
|
67
|
+
orientation = exif_get_short(ee->data, bo);
|
68
|
+
}
|
69
|
+
|
70
|
+
exif_data_free(ed);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
return orientation;
|
76
|
+
}
|
77
|
+
|
78
|
+
/* Sets the image orientation */
|
79
|
+
static void av_set_orientation(VipsImage* image, int orientation)
|
80
|
+
{
|
81
|
+
GType exif_type = vips_image_get_typeof(image, VIPS_META_EXIF_NAME);
|
82
|
+
if(exif_type != 0)
|
83
|
+
{
|
84
|
+
unsigned char *data;
|
85
|
+
size_t data_length;
|
86
|
+
if(!vips_image_get_blob(image, VIPS_META_EXIF_NAME, (void *)&data, &data_length))
|
87
|
+
{
|
88
|
+
ExifData *ed;
|
89
|
+
ed = exif_data_new_from_data(data, data_length);
|
90
|
+
if(ed != NULL)
|
91
|
+
{
|
92
|
+
ExifByteOrder bo = exif_data_get_byte_order(ed);
|
93
|
+
ExifEntry *ee = exif_data_get_entry(ed, EXIF_TAG_ORIENTATION);
|
94
|
+
if(ee)
|
95
|
+
{
|
96
|
+
exif_set_short(ee->data, bo, (short)orientation);
|
97
|
+
vips_image_set_blob(image, VIPS_META_EXIF_NAME, NULL, (void *)ed, data_length);
|
98
|
+
}
|
99
|
+
|
100
|
+
exif_data_free(ed);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
/* Shrinks image using the provided width and height ratios */
|
108
|
+
static VipsImage* av_internal_shrink_image(VipsImage* image, double width_ratio, double height_ratio, char** err_str)
|
109
|
+
{
|
110
|
+
VipsImage* t = im_open("temp-image", "p");
|
111
|
+
if(!t)
|
112
|
+
{
|
113
|
+
*err_str = copy_vips_error();
|
114
|
+
return NULL;
|
115
|
+
}
|
116
|
+
|
117
|
+
if(im_shrink(image, t, width_ratio, height_ratio))
|
118
|
+
{
|
119
|
+
*err_str = copy_vips_error();
|
120
|
+
im_close(t);
|
121
|
+
return NULL;
|
122
|
+
}
|
123
|
+
|
124
|
+
return t;
|
125
|
+
}
|
126
|
+
|
127
|
+
/* Rotates the image */
|
128
|
+
static VipsImage* av_internal_rotate(VipsImage* in, VipsAngle angle, char** err_str)
|
129
|
+
{
|
130
|
+
VipsImage* t = im_open("temp-image", "p");
|
131
|
+
if(!t)
|
132
|
+
{
|
133
|
+
*err_str = copy_vips_error();
|
134
|
+
return NULL;
|
135
|
+
}
|
136
|
+
|
137
|
+
if(vips_rot(in, &t, angle, NULL))
|
138
|
+
{
|
139
|
+
*err_str = copy_vips_error();
|
140
|
+
return NULL;
|
141
|
+
}
|
142
|
+
|
143
|
+
return t;
|
144
|
+
}
|
145
|
+
|
146
|
+
/* Flips the image */
|
147
|
+
static VipsImage* av_internal_flip(VipsImage* in, VipsDirection direction, char** err_str)
|
148
|
+
{
|
149
|
+
VipsImage* t = im_open("temp-image", "p");
|
150
|
+
if(!t)
|
151
|
+
{
|
152
|
+
*err_str = copy_vips_error();
|
153
|
+
return NULL;
|
154
|
+
}
|
155
|
+
|
156
|
+
if(vips_flip(in, &t, direction, NULL))
|
157
|
+
{
|
158
|
+
*err_str = copy_vips_error();
|
159
|
+
return NULL;
|
160
|
+
}
|
161
|
+
|
162
|
+
return t;
|
163
|
+
}
|
164
|
+
|
165
|
+
/* Rotates & Flips the image */
|
166
|
+
static VipsImage* av_internal_rotate_flip(VipsImage* in, VipsAngle angle, VipsDirection direction, char** err_str)
|
167
|
+
{
|
168
|
+
VipsImage* t;
|
169
|
+
t = av_internal_rotate(in, angle, err_str);
|
170
|
+
if(t)
|
171
|
+
{
|
172
|
+
VipsImage* f;
|
173
|
+
f = av_internal_flip(t, direction, err_str);
|
174
|
+
if(f)
|
175
|
+
{
|
176
|
+
im_close(t);
|
177
|
+
t = f;
|
178
|
+
}
|
179
|
+
else
|
180
|
+
{
|
181
|
+
im_close(t);
|
182
|
+
t = NULL;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
return t;
|
187
|
+
}
|
188
|
+
|
189
|
+
/*
|
190
|
+
Transforms image orientation
|
191
|
+
1) = NONE
|
192
|
+
2) = FLIP_H
|
193
|
+
3) = ROT_180
|
194
|
+
4) = FLIP_V
|
195
|
+
5) = TRANSPOSE
|
196
|
+
6) = ROT_90
|
197
|
+
7) = TRANSVERSE
|
198
|
+
8) = ROT_270
|
199
|
+
*/
|
200
|
+
static VipsImage* av_internal_transform_image_orientation(VipsImage* image, int orientation, char** err_str)
|
201
|
+
{
|
202
|
+
VipsImage* res = NULL;
|
203
|
+
|
204
|
+
switch(orientation)
|
205
|
+
{
|
206
|
+
case 1:
|
207
|
+
// no-op
|
208
|
+
break;
|
209
|
+
|
210
|
+
case 2:
|
211
|
+
res = av_internal_flip(image, VIPS_DIRECTION_HORIZONTAL, err_str);
|
212
|
+
break;
|
213
|
+
|
214
|
+
case 3:
|
215
|
+
res = av_internal_rotate(image, VIPS_ANGLE_180, err_str);
|
216
|
+
break;
|
217
|
+
|
218
|
+
case 4:
|
219
|
+
res = av_internal_flip(image, VIPS_DIRECTION_VERTICAL, err_str);
|
220
|
+
break;
|
221
|
+
|
222
|
+
case 5:
|
223
|
+
res = av_internal_rotate_flip(image, VIPS_ANGLE_90, VIPS_DIRECTION_HORIZONTAL, err_str);
|
224
|
+
break;
|
225
|
+
|
226
|
+
case 6:
|
227
|
+
res = av_internal_rotate(image, VIPS_ANGLE_90, err_str);
|
228
|
+
break;
|
229
|
+
|
230
|
+
case 7:
|
231
|
+
res = av_internal_rotate_flip(image, VIPS_ANGLE_270, VIPS_DIRECTION_HORIZONTAL, err_str);
|
232
|
+
break;
|
233
|
+
|
234
|
+
case 8:
|
235
|
+
res = av_internal_rotate(image, VIPS_ANGLE_270, err_str);
|
236
|
+
break;
|
237
|
+
|
238
|
+
default:
|
239
|
+
// no-op
|
240
|
+
break;
|
241
|
+
}
|
242
|
+
|
243
|
+
if(res)
|
244
|
+
{
|
245
|
+
av_set_orientation(res, 1);
|
246
|
+
}
|
247
|
+
|
248
|
+
return res;
|
249
|
+
}
|
250
|
+
|
251
|
+
|
252
|
+
/* Thread function for image processing */
|
253
|
+
void* av_build_image_thread_func(void* data)
|
254
|
+
{
|
255
|
+
transform_data_t* tdata = (transform_data_t*)data;
|
256
|
+
if(!tdata)
|
257
|
+
return NULL;
|
258
|
+
|
259
|
+
VipsImage* image;
|
260
|
+
image = vips_image_new_mode(tdata->src_path, "r");
|
261
|
+
if(image)
|
262
|
+
{
|
263
|
+
// ORIENTATION
|
264
|
+
int is_transform_orientation = tdata->natural_orientation;
|
265
|
+
int orientation = av_get_orientation(image);
|
266
|
+
//fprintf(stderr, "orientation: %d\n", orientation);
|
267
|
+
|
268
|
+
// SHRINK
|
269
|
+
if(tdata->dst_path && tdata->target_width && tdata->target_height)
|
270
|
+
{
|
271
|
+
double width_ratio = 0, height_ratio = 0;
|
272
|
+
|
273
|
+
av_get_scale_transform2(image->Xsize, image->Ysize,
|
274
|
+
tdata->target_width, tdata->target_height,
|
275
|
+
image_scale_fit_no_scale_up,
|
276
|
+
&width_ratio, &height_ratio);
|
277
|
+
|
278
|
+
VipsImage* t;
|
279
|
+
t = av_internal_shrink_image(image, width_ratio, height_ratio, &tdata->err_str);
|
280
|
+
if(t)
|
281
|
+
{
|
282
|
+
if(is_transform_orientation && orientation > 1)
|
283
|
+
{
|
284
|
+
// Need to transform an image so that orientation becomes 1
|
285
|
+
VipsImage* tran;
|
286
|
+
tran = av_internal_transform_image_orientation(t, orientation, &tdata->err_str);
|
287
|
+
if(tran)
|
288
|
+
{
|
289
|
+
im_close(t);
|
290
|
+
t = tran;
|
291
|
+
}
|
292
|
+
}
|
293
|
+
|
294
|
+
VipsImage* out;
|
295
|
+
out = vips_image_new_mode(tdata->dst_path, "w");
|
296
|
+
if(out)
|
297
|
+
{
|
298
|
+
if(im_copy(t, out))
|
299
|
+
{
|
300
|
+
tdata->err_str = copy_vips_error();
|
301
|
+
}
|
302
|
+
|
303
|
+
tdata->final_width = out->Xsize;
|
304
|
+
tdata->final_height = out->Ysize;
|
305
|
+
|
306
|
+
im_close(out);
|
307
|
+
|
308
|
+
av_get_image_file_size(tdata->dst_path, &tdata->final_size);
|
309
|
+
}
|
310
|
+
else
|
311
|
+
{
|
312
|
+
tdata->err_str = copy_vips_error();
|
313
|
+
}
|
314
|
+
|
315
|
+
im_close(t);
|
316
|
+
}
|
317
|
+
}
|
318
|
+
else
|
319
|
+
{
|
320
|
+
tdata->final_width = image->Xsize;
|
321
|
+
tdata->final_height = image->Ysize;
|
322
|
+
av_get_image_file_size(tdata->src_path, &tdata->final_size);
|
323
|
+
}
|
324
|
+
|
325
|
+
im_close(image);
|
326
|
+
}
|
327
|
+
|
328
|
+
av_add_to_event_queue(tdata);
|
329
|
+
|
330
|
+
return NULL;
|
331
|
+
}
|
332
|
+
|
333
|
+
/* Image transformation */
|
334
|
+
static VALUE av_transform(int argc, VALUE *argv, VALUE self)
|
335
|
+
{
|
336
|
+
rb_need_block();
|
337
|
+
VALUE proc = rb_block_proc();
|
338
|
+
|
339
|
+
VALUE rest;
|
340
|
+
rb_scan_args(argc, argv, "*", &rest);
|
341
|
+
|
342
|
+
VALUE params = rb_ary_pop(rest);
|
343
|
+
VALUE tmp = rb_check_hash_type(params);
|
344
|
+
if (NIL_P(tmp))
|
345
|
+
rb_raise(rb_eArgError, "No transformation parameters specified");
|
346
|
+
|
347
|
+
// Parse options
|
348
|
+
VALUE load = rb_hash_aref(params, ID2SYM(av_t_id_load));
|
349
|
+
if(NIL_P(load))
|
350
|
+
rb_raise(rb_eArgError, "No image source specified: transform(:load => 'image.jpg')");
|
351
|
+
|
352
|
+
VALUE save = rb_hash_aref(params, ID2SYM(av_t_id_save));
|
353
|
+
if(NIL_P(save))
|
354
|
+
rb_raise(rb_eArgError, "No image destination specified: transform(:save => 'output.jpg')");
|
355
|
+
|
356
|
+
VALUE scale_x = rb_hash_aref(params, ID2SYM(av_t_id_scale_x));
|
357
|
+
VALUE scale_y = rb_hash_aref(params, ID2SYM(av_t_id_scale_y));
|
358
|
+
|
359
|
+
if(NIL_P(scale_x) && NIL_P(scale_y))
|
360
|
+
rb_raise(rb_eArgError, "No scale width or height specified of the source image: transform(:scale_x => 800, :scale_y => 600)");
|
361
|
+
|
362
|
+
if(NIL_P(scale_y))
|
363
|
+
scale_y = scale_x;
|
364
|
+
|
365
|
+
if(NIL_P(scale_x))
|
366
|
+
scale_x = scale_y;
|
367
|
+
|
368
|
+
VALUE natural_orient_flag = rb_hash_aref(params, ID2SYM(av_t_id_natural_orientation));
|
369
|
+
if(!NIL_P(natural_orient_flag) &&
|
370
|
+
(TYPE(natural_orient_flag) != T_TRUE) && (TYPE(natural_orient_flag) != T_FALSE))
|
371
|
+
rb_raise(rb_eArgError, "Invalid natural orientation: transform(:natural_orientation => true|false)");
|
372
|
+
|
373
|
+
transform_data_t* tdata = av_make_transform_data(StringValuePtr(load), StringValuePtr(save));
|
374
|
+
tdata->target_width = NUM2INT(scale_x);
|
375
|
+
tdata->target_height = NUM2INT(scale_y);
|
376
|
+
tdata->natural_orientation = (TYPE(natural_orient_flag) == T_TRUE ? 1 : 0);
|
377
|
+
tdata->proc = proc;
|
378
|
+
|
379
|
+
rb_gc_register_address(&tdata->proc);
|
380
|
+
|
381
|
+
av_enqueue_task(av_build_image_thread_func, tdata);
|
382
|
+
|
383
|
+
return self;
|
384
|
+
}
|
385
|
+
|
386
|
+
/* Initialize transformation pipeline */
|
387
|
+
void init_async_vips_transform(void)
|
388
|
+
{
|
389
|
+
rb_define_singleton_method(mAsyncVips, "transform", av_transform, -1);
|
390
|
+
|
391
|
+
av_t_id_load = rb_intern("load");
|
392
|
+
av_t_id_save = rb_intern("save");
|
393
|
+
av_t_id_scale_x = rb_intern("scale_x");
|
394
|
+
av_t_id_scale_y = rb_intern("scale_y");
|
395
|
+
av_t_id_natural_orientation = rb_intern("natural_orientation");
|
396
|
+
}
|