async-ruby-vips 1.2.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.
- 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
|
+
}
|