1 /**
2 * C layer of the php-vips binding.
3 */
4
5 /* Uncomment for some logging.
6 #define VIPS_DEBUG
7 */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "php.h"
14 #include "php_ini.h"
15 #include "ext/standard/info.h"
16 #include "SAPI.h"
17 #include "php_vips.h"
18
19 #include <vips/vips.h>
20 #include <vips/debug.h>
21 #include <vips/vector.h>
22
23 /* If you declare any globals in php_vips.h uncomment this:
24 ZEND_DECLARE_MODULE_GLOBALS(vips)
25 */
26
27 /* True global resources - no need for thread safety here */
28 static int le_gobject;
29
30 /* {{{ PHP_INI
31 */
32 /* Remove comments and fill if you need to have entries in php.ini
33 PHP_INI_BEGIN()
34 STD_PHP_INI_ENTRY("vips.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_vips_globals, vips_globals)
35 STD_PHP_INI_ENTRY("vips.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_vips_globals, vips_globals)
36 PHP_INI_END()
37 */
38 /* }}} */
39
40 /* {{{ proto static int vips_php_call_array(const char *operation_name, zval *instance, const char *option_string, int argc, zval *argv, zval *return_value)
41 Call any vips operation. */
42
43 /* Track stuff during a call to a vips operation in one of these.
44 */
45 typedef struct _VipsPhpCall {
46 /* Parameters.
47 */
48 const char *operation_name;
49 zval *instance;
50 const char *option_string;
51 int argc;
52 zval *argv;
53
54 /* The operation we are calling.
55 */
56 VipsOperation *operation;
57
58 /* The num of args this operation needs from php. This does not include the
59 * @instance zval.
60 */
61 int args_required;
62
63 /* If we've already used the instance zval.
64 */
65 gboolean used_instance;
66
67 /* Extra php array of optional args.
68 */
69 zval *options;
70
71 /* The first image arg ... the thing we expand constants to match.
72 */
73 VipsImage *match_image;
74
75 } VipsPhpCall;
76
77 static void
vips_php_call_free(VipsPhpCall * call)78 vips_php_call_free(VipsPhpCall *call)
79 {
80 VIPS_DEBUG_MSG("vips_php_call_free:\n");
81
82 VIPS_UNREF(call->operation);
83 g_free(call);
84 }
85
86 static VipsPhpCall *
vips_php_call_new(const char * operation_name,zval * instance,const char * option_string,int argc,zval * argv)87 vips_php_call_new(const char *operation_name, zval *instance,
88 const char *option_string, int argc, zval *argv)
89 {
90 VipsPhpCall *call;
91
92 VIPS_DEBUG_MSG("vips_php_call_new: %s\n", operation_name );
93 VIPS_DEBUG_MSG(" option_string = \"%s\", argc = %d\n",
94 option_string, argc);
95
96 call = g_new0( VipsPhpCall, 1 );
97 call->operation_name = operation_name;
98 call->instance = instance;
99 call->option_string = option_string;
100 call->argc = argc;
101 call->argv = argv;
102
103 if (!(call->operation = vips_operation_new(operation_name))) {
104 vips_php_call_free(call);
105 return NULL;
106 }
107
108 return call;
109 }
110
111 /* Get a non-reference zval. In php7, zvalues can be references to other zvals
112 * ... chase down a chain of refs to get a real zval.
113 * the ref pointer chain.
114 */
115 static inline zval *
zval_get_nonref(zval * zvalue)116 zval_get_nonref(zval *zvalue)
117 {
118 while (Z_TYPE_P(zvalue) == IS_REFERENCE)
119 zvalue = Z_REFVAL_P(zvalue);
120
121 return zvalue;
122 }
123
124 /* First pass over our arguments: find the first image arg and note as
125 * match_image.
126 */
127 static void
vips_php_analyze_arg(VipsPhpCall * call,zval * zvalue)128 vips_php_analyze_arg(VipsPhpCall *call, zval *zvalue)
129 {
130 zvalue = zval_get_nonref(zvalue);
131
132 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
133 const int n = zend_hash_num_elements(Z_ARRVAL_P(zvalue));
134
135 int i;
136
137 for (i = 0; i < n; i++) {
138 zval *item = zend_hash_index_find(Z_ARRVAL_P(zvalue), i);
139
140 if (item) {
141 vips_php_analyze_arg(call, item);
142 }
143 }
144 }
145 else if (Z_TYPE_P(zvalue) == IS_RESOURCE) {
146 VipsImage *image;
147
148 if( (image = (VipsImage *)zend_fetch_resource(Z_RES_P(zvalue),
149 "GObject", le_gobject)) != NULL) {
150 if (!call->match_image) {
151 call->match_image = image;
152 }
153 }
154 }
155 }
156
157 static int
vips_php_blob_free(void * buf,void * area)158 vips_php_blob_free(void *buf, void *area)
159 {
160 g_free(buf);
161
162 return 0;
163 }
164
165 /* Expand a constant (eg. 12, "12" or [1, 2, 3]) into an image using
166 * @match_image as a guide.
167 */
168 static VipsImage *
expand_constant(VipsImage * match_image,zval * constant)169 expand_constant(VipsImage *match_image, zval *constant)
170 {
171 VipsImage *result;
172 VipsImage *x;
173
174 if (vips_black(&result, 1, 1, NULL)) {
175 return NULL;
176 }
177
178 constant = zval_get_nonref(constant);
179
180 if (Z_TYPE_P(constant) == IS_ARRAY) {
181 const int n = zend_hash_num_elements(Z_ARRVAL_P(constant));
182
183 double *ones;
184 double *offsets;
185 int i;
186
187 ones = VIPS_ARRAY(result, n, double);
188 offsets = VIPS_ARRAY(result, n, double);
189
190 for (i = 0; i < n; i++) {
191 zval *ele;
192
193 ones[i] = 1.0;
194
195 if ((ele = zend_hash_index_find(Z_ARRVAL_P(constant), i)) != NULL) {
196 offsets[i] = zval_get_double(ele);
197 }
198 }
199
200 if (vips_linear(result, &x, ones, offsets, n, NULL)) {
201 return NULL;
202 }
203 g_object_unref(result);
204 result = x;
205 }
206 else {
207 if (vips_linear1(result, &x, 1.0, zval_get_double(constant), NULL)) {
208 return NULL;
209 }
210 g_object_unref(result);
211 result = x;
212 }
213
214 if (vips_cast(result, &x, match_image->BandFmt, NULL)) {
215 return NULL;
216 }
217 g_object_unref(result);
218 result = x;
219
220 if (vips_embed(result, &x, 0, 0, match_image->Xsize, match_image->Ysize,
221 "extend", VIPS_EXTEND_COPY,
222 NULL)) {
223 return NULL;
224 }
225 g_object_unref(result);
226 result = x;
227
228 result->Type = match_image->Type;
229 result->Xres = match_image->Xres;
230 result->Yres = match_image->Yres;
231 result->Xoffset = match_image->Xoffset;
232 result->Yoffset = match_image->Yoffset;
233
234 return result;
235 }
236
237 /* Is a zval a rectangular 2D array.
238 */
239 static gboolean
is_2D(zval * array)240 is_2D(zval *array)
241 {
242 int height;
243 zval *row;
244 int width;
245 int y;
246
247 array = zval_get_nonref(array);
248
249 if (Z_TYPE_P(array) != IS_ARRAY) {
250 return FALSE;
251 }
252
253 height = zend_hash_num_elements(Z_ARRVAL_P(array));
254 if ((row = zend_hash_index_find(Z_ARRVAL_P(array), 0)) == NULL ||
255 !(row = zval_get_nonref(row)) ||
256 Z_TYPE_P(row) != IS_ARRAY) {
257 return FALSE;
258 }
259 width = zend_hash_num_elements(Z_ARRVAL_P(row));
260
261 for (y = 1; y < height; y++) {
262 if ((row = zend_hash_index_find(Z_ARRVAL_P(array), y)) == NULL ||
263 !(row = zval_get_nonref(row)) ||
264 Z_TYPE_P(row) != IS_ARRAY ||
265 zend_hash_num_elements(Z_ARRVAL_P(row)) != width) {
266 return FALSE;
267 }
268 }
269
270 return TRUE;
271 }
272
273 /* Make a vips matrix image from a 2D zval. @array must have passed is_2D()
274 * before calling this.
275 */
276 static VipsImage *
matrix_from_zval(zval * array)277 matrix_from_zval(zval *array)
278 {
279 int width;
280 int height;
281 zval *row;
282 VipsImage *mat;
283 int x, y;
284
285 array = zval_get_nonref(array);
286
287 height = zend_hash_num_elements(Z_ARRVAL_P(array));
288 row = zend_hash_index_find(Z_ARRVAL_P(array), 0);
289 row = zval_get_nonref(row);
290 g_assert(Z_TYPE_P(row) == IS_ARRAY);
291 width = zend_hash_num_elements(Z_ARRVAL_P(row));
292 mat = vips_image_new_matrix(width, height);
293
294 for (y = 0; y < height; y++) {
295 row = zend_hash_index_find(Z_ARRVAL_P(array), y);
296 row = zval_get_nonref(row);
297 g_assert(Z_TYPE_P(row) == IS_ARRAY);
298 g_assert(zend_hash_num_elements(Z_ARRVAL_P(row)) == width);
299
300 for (x = 0; x < width; x++) {
301 zval *ele;
302
303 ele = zend_hash_index_find(Z_ARRVAL_P(row), x);
304 *VIPS_MATRIX(mat, x, y) = zval_get_double(ele);
305 }
306 }
307
308 return mat;
309 }
310
311 /* Turn a zval into an image. An image stays an image, a 2D array of numbers
312 * becomes a matrix image, a 1D array or a simple constant is expanded to
313 * match @match_image.
314 */
315 static VipsImage *
imageize(VipsImage * match_image,zval * zvalue)316 imageize(VipsImage *match_image, zval *zvalue)
317 {
318 VipsImage *image;
319
320 zvalue = zval_get_nonref(zvalue);
321
322 if (Z_TYPE_P(zvalue) == IS_RESOURCE &&
323 (image = (VipsImage *)
324 zend_fetch_resource(Z_RES_P(zvalue), "GObject", le_gobject))) {
325 return image;
326 }
327 else if (is_2D(zvalue)) {
328 return matrix_from_zval(zvalue);
329 }
330 else if (match_image) {
331 return expand_constant(match_image, zvalue);
332 }
333 else {
334 php_error_docref(NULL, E_WARNING, "not a VipsImage");
335 return NULL;
336 }
337 }
338
339 static int
zval_to_array_image(VipsImage * match_image,zval * zvalue,GValue * gvalue)340 zval_to_array_image(VipsImage *match_image, zval *zvalue, GValue *gvalue)
341 {
342 VipsImage **arr;
343 VipsImage *image;
344 int n;
345 int i;
346
347 zvalue = zval_get_nonref(zvalue);
348
349 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
350 n = zend_hash_num_elements(Z_ARRVAL_P(zvalue));
351 }
352 else {
353 n = 1;
354 }
355
356 vips_value_set_array_image(gvalue, n);
357 arr = vips_value_get_array_image(gvalue, NULL);
358
359 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
360 for (i = 0; i < n; i++) {
361 zval *ele;
362
363 ele = zend_hash_index_find(Z_ARRVAL_P(zvalue), i);
364 if (!ele) {
365 php_error_docref(NULL, E_WARNING, "element missing from array");
366 return -1;
367 }
368
369 if (!(image = imageize(match_image, ele))) {
370 return -1;
371 }
372
373 arr[i] = image;
374 g_object_ref(image);
375 }
376 }
377 else {
378 if (!(image = imageize(match_image, zvalue))) {
379 return -1;
380 }
381
382 arr[0] = image;
383 g_object_ref(image);
384 }
385
386 return 0;
387 }
388
389 /* Set a gvalue from a php value.
390 *
391 * You must set the type of the gvalue before calling this to hint what kind
392 * of gvalue to make. For example if type is an enum, a zval string will be
393 * used to look up the enum nick.
394 *
395 * If non-NULL, @match_image is used to turn constants into images.
396 */
397 static int
vips_php_zval_to_gval(VipsImage * match_image,zval * zvalue,GValue * gvalue)398 vips_php_zval_to_gval(VipsImage *match_image, zval *zvalue, GValue *gvalue)
399 {
400 GType type = G_VALUE_TYPE(gvalue);
401
402 /* The fundamental type ... eg. G_TYPE_ENUM for a VIPS_TYPE_KERNEL, or
403 * G_TYPE_OBJECT for VIPS_TYPE_IMAGE().
404 */
405 GType fundamental = G_TYPE_FUNDAMENTAL(type);
406
407 VipsImage *image;
408 zend_string *zstr;
409 int enum_value;
410
411 switch (fundamental) {
412 case G_TYPE_STRING:
413 /* These are GStrings, vips refstrings are handled by boxed, see
414 * below.
415 */
416 zstr = zval_get_string(zvalue);
417 g_value_set_string(gvalue, ZSTR_VAL(zstr));
418 zend_string_release(zstr);
419 break;
420
421 case G_TYPE_OBJECT:
422 if (!(image = imageize(match_image, zvalue))) {
423 return -1;
424 }
425 g_value_set_object(gvalue, image);
426 break;
427
428 case G_TYPE_INT:
429 g_value_set_int(gvalue, zval_get_long(zvalue));
430 break;
431
432 case G_TYPE_UINT64:
433 g_value_set_uint64(gvalue, zval_get_long(zvalue));
434 break;
435
436 case G_TYPE_BOOLEAN:
437 g_value_set_boolean(gvalue, zval_get_long(zvalue));
438 break;
439
440 case G_TYPE_ENUM:
441 zvalue = zval_get_nonref(zvalue);
442
443 if (Z_TYPE_P(zvalue) == IS_LONG) {
444 enum_value = Z_LVAL_P(zvalue);
445 }
446 else if (Z_TYPE_P(zvalue) == IS_DOUBLE) {
447 enum_value = Z_DVAL_P(zvalue);
448 }
449 else {
450 zstr = zval_get_string(zvalue);
451 enum_value = vips_enum_from_nick("enum", type, ZSTR_VAL(zstr));
452 if (enum_value < 0) {
453 zend_string_release(zstr);
454 return -1;
455 }
456 zend_string_release(zstr);
457 }
458 g_value_set_enum(gvalue, enum_value);
459 break;
460
461 case G_TYPE_FLAGS:
462 g_value_set_flags(gvalue, zval_get_long(zvalue));
463 break;
464
465 case G_TYPE_DOUBLE:
466 g_value_set_double(gvalue, zval_get_double(zvalue));
467 break;
468
469 case G_TYPE_BOXED:
470 if (type == VIPS_TYPE_REF_STRING) {
471 zstr = zval_get_string(zvalue);
472 vips_value_set_ref_string(gvalue, ZSTR_VAL(zstr));
473 zend_string_release(zstr);
474 }
475 else if (type == VIPS_TYPE_BLOB) {
476 void *buf;
477
478 zvalue = zval_get_nonref(zvalue);
479
480 zstr = zval_get_string(zvalue);
481 buf = g_malloc(ZSTR_LEN(zstr));
482 memcpy(buf, ZSTR_VAL(zstr), ZSTR_LEN(zstr));
483 zend_string_release(zstr);
484
485 vips_value_set_blob(gvalue,
486 vips_php_blob_free, buf, Z_STRLEN_P(zvalue));
487 }
488 else if (type == VIPS_TYPE_ARRAY_INT) {
489 int *arr;
490 int n;
491 int i;
492
493 zvalue = zval_get_nonref(zvalue);
494
495 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
496 n = zend_hash_num_elements(Z_ARRVAL_P(zvalue));
497 }
498 else {
499 n = 1;
500 }
501
502 vips_value_set_array_int(gvalue, NULL, n);
503 arr = vips_value_get_array_int(gvalue, NULL);
504
505 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
506 for (i = 0; i < n; i++) {
507 zval *ele;
508
509 ele = zend_hash_index_find(Z_ARRVAL_P(zvalue), i);
510 if (ele) {
511 arr[i] = zval_get_long(ele);
512 }
513 }
514 }
515 else {
516 arr[0] = zval_get_long(zvalue);
517 }
518 }
519 else if (type == VIPS_TYPE_ARRAY_DOUBLE) {
520 double *arr;
521 int n;
522 int i;
523
524 zvalue = zval_get_nonref(zvalue);
525
526 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
527 n = zend_hash_num_elements(Z_ARRVAL_P(zvalue));
528 }
529 else {
530 n = 1;
531 }
532
533 vips_value_set_array_double(gvalue, NULL, n);
534 arr = vips_value_get_array_double(gvalue, NULL);
535
536 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
537 for (i = 0; i < n; i++) {
538 zval *ele;
539
540 ele = zend_hash_index_find(Z_ARRVAL_P(zvalue), i);
541 if (ele) {
542 arr[i] = zval_get_double(ele);
543 }
544 }
545 }
546 else {
547 arr[0] = zval_get_double(zvalue);
548 }
549 }
550 else if (type == VIPS_TYPE_ARRAY_IMAGE) {
551 if (zval_to_array_image(match_image, zvalue, gvalue)) {
552 return -1;
553 }
554 }
555 else {
556 g_warning( "%s: unimplemented boxed type %s",
557 G_STRLOC, g_type_name(type) );
558 }
559 break;
560
561 default:
562 g_warning( "%s: unimplemented GType %s",
563 G_STRLOC, g_type_name(fundamental) );
564 break;
565 }
566
567 return 0;
568 }
569
570 static int
vips_php_set_value(VipsPhpCall * call,GParamSpec * pspec,VipsArgumentFlags flags,zval * zvalue)571 vips_php_set_value(VipsPhpCall *call,
572 GParamSpec *pspec, VipsArgumentFlags flags, zval *zvalue)
573 {
574 const char *name = g_param_spec_get_name(pspec);
575 GType pspec_type = G_PARAM_SPEC_VALUE_TYPE(pspec);
576 GValue gvalue = { 0 };
577
578 g_value_init(&gvalue, pspec_type);
579 if (vips_php_zval_to_gval(call->match_image, zvalue, &gvalue)) {
580 g_value_unset(&gvalue);
581 return -1;
582 }
583
584 /* If we are setting a MODIFY VipsArgument with an image, we need to take a
585 * copy.
586 */
587 if (g_type_is_a(pspec_type, VIPS_TYPE_IMAGE) &&
588 (flags & VIPS_ARGUMENT_MODIFY)) {
589 VipsImage *image;
590 VipsImage *memory;
591
592 VIPS_DEBUG_MSG("vips_php_set_value: copying image\n");
593
594 image = (VipsImage *) g_value_get_object(&gvalue);
595 memory = vips_image_new_memory();
596 if (vips_image_write(image, memory)) {
597 g_object_unref(memory);
598 g_value_unset(&gvalue);
599 return -1;
600 }
601 g_value_unset(&gvalue);
602 g_value_init(&gvalue, pspec_type);
603 g_value_set_object(&gvalue, memory);
604 }
605
606 #ifdef VIPS_DEBUG
607 {
608 char *str_value;
609
610 str_value = g_strdup_value_contents(&gvalue);
611 VIPS_DEBUG_MSG(" %s.%s = %s\n", call->operation_name, name, str_value);
612 g_free(str_value);
613 }
614 #endif/*VIPS_DEBUG*/
615
616 g_object_set_property(G_OBJECT(call->operation), name, &gvalue);
617 g_value_unset(&gvalue);
618
619 return 0;
620 }
621
622 static void *
vips_php_set_required_input(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)623 vips_php_set_required_input(VipsObject *object,
624 GParamSpec *pspec, VipsArgumentClass *argument_class,
625 VipsArgumentInstance *argument_instance,
626 void *a, void *b)
627 {
628 VipsPhpCall *call = (VipsPhpCall *) a;
629
630 if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
631 (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
632 (argument_class->flags & VIPS_ARGUMENT_INPUT) &&
633 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
634 !argument_instance->assigned) {
635 zval *arg;
636
637 /* If this arg needs an image, we use instance, if we can.
638 */
639 arg = NULL;
640 if (G_PARAM_SPEC_VALUE_TYPE(pspec) == VIPS_TYPE_IMAGE &&
641 call->instance &&
642 !call->used_instance) {
643 arg = call->instance;
644 call->used_instance = TRUE;
645 }
646 else if (call->args_required < call->argc) {
647 /* Pick the next zval off the supplied arg list.
648 */
649 arg = &call->argv[call->args_required];
650 call->args_required += 1;
651 }
652
653 if (arg &&
654 vips_php_set_value(call, pspec, argument_class->flags, arg)) {
655 return call;
656 }
657 }
658
659 return NULL;
660 }
661
662 /* Set all optional arguments.
663 */
664 static int
vips_php_set_optional_input(VipsPhpCall * call,zval * options)665 vips_php_set_optional_input(VipsPhpCall *call, zval *options)
666 {
667 zend_string *key;
668 zval *value;
669
670 VIPS_DEBUG_MSG("vips_php_set_optional_input:\n");
671
672 options = zval_get_nonref(options);
673
674 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), key, value) {
675 char *name;
676 GParamSpec *pspec;
677 VipsArgumentClass *argument_class;
678 VipsArgumentInstance *argument_instance;
679
680 if (key == NULL) {
681 continue;
682 }
683
684 name = ZSTR_VAL(key);
685 if (vips_object_get_argument(VIPS_OBJECT(call->operation), name,
686 &pspec, &argument_class, &argument_instance)) {
687 return -1;
688 }
689
690 if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
691 (argument_class->flags & VIPS_ARGUMENT_INPUT) &&
692 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED) &&
693 vips_php_set_value(call, pspec, argument_class->flags, value)) {
694 return -1;
695 }
696 } ZEND_HASH_FOREACH_END();
697
698 return 0;
699 }
700
701 /* Set a php zval from a gvalue.
702 */
703 static int
vips_php_gval_to_zval(GValue * gvalue,zval * zvalue)704 vips_php_gval_to_zval(GValue *gvalue, zval *zvalue)
705 {
706 GType type = G_VALUE_TYPE(gvalue);
707
708 /* The fundamental type ... eg. G_TYPE_ENUM for a VIPS_TYPE_KERNEL, or
709 * G_TYPE_OBJECT for VIPS_TYPE_IMAGE().
710 */
711 GType fundamental = G_TYPE_FUNDAMENTAL(type);
712
713 const char *str;
714 GObject *gobject;
715 zend_resource *resource;
716 int enum_value;
717
718 switch (fundamental) {
719 case G_TYPE_STRING:
720 /* These are GStrings, vips refstrings are handled by boxed, see
721 * below.
722 */
723 str = g_value_get_string(gvalue);
724 ZVAL_STRING(zvalue, str);
725 break;
726
727 case G_TYPE_OBJECT:
728 gobject = g_value_get_object(gvalue);
729 resource = zend_register_resource(gobject, le_gobject);
730 ZVAL_RES(zvalue, resource);
731 break;
732
733 case G_TYPE_INT:
734 ZVAL_LONG(zvalue, g_value_get_int(gvalue));
735 break;
736
737 case G_TYPE_UINT64:
738 ZVAL_LONG(zvalue, g_value_get_uint64(gvalue));
739 break;
740
741 case G_TYPE_BOOLEAN:
742 ZVAL_LONG(zvalue, g_value_get_boolean(gvalue));
743 break;
744
745 case G_TYPE_ENUM:
746 enum_value = g_value_get_enum(gvalue);
747 str = vips_enum_nick(type, enum_value);
748 ZVAL_STRING(zvalue, str);
749 break;
750
751 case G_TYPE_FLAGS:
752 ZVAL_LONG(zvalue, g_value_get_flags(gvalue));
753 break;
754
755 case G_TYPE_DOUBLE:
756 ZVAL_DOUBLE(zvalue, g_value_get_double(gvalue));
757 break;
758
759 case G_TYPE_BOXED:
760 if (type == VIPS_TYPE_REF_STRING ||
761 type == VIPS_TYPE_BLOB) {
762 const char *str;
763 size_t str_len;
764
765 str = vips_value_get_ref_string(gvalue, &str_len);
766 ZVAL_STRINGL(zvalue, str, str_len);
767 }
768 else if (type == VIPS_TYPE_ARRAY_DOUBLE) {
769 double *arr;
770 int n;
771 int i;
772
773 arr = vips_value_get_array_double(gvalue, &n);
774 array_init(zvalue);
775 for (i = 0; i < n; i++) {
776 add_next_index_double(zvalue, arr[i]);
777 }
778 }
779 else if (type == VIPS_TYPE_ARRAY_INT) {
780 int *arr;
781 int n;
782 int i;
783
784 arr = vips_value_get_array_int(gvalue, &n);
785 array_init(zvalue);
786 for (i = 0; i < n; i++) {
787 add_next_index_long(zvalue, arr[i]);
788 }
789 }
790 else if (type == VIPS_TYPE_ARRAY_IMAGE) {
791 VipsImage **arr;
792 int n;
793 int i;
794
795 arr = vips_value_get_array_image(gvalue, &n);
796 array_init(zvalue);
797 for (i = 0; i < n; i++) {
798 zval x;
799
800 g_object_ref(arr[i]);
801 resource = zend_register_resource(arr[i], le_gobject);
802 ZVAL_RES(&x, resource);
803 add_next_index_zval(zvalue, &x);
804 }
805 }
806 else {
807 g_warning( "%s: unimplemented boxed type %s",
808 G_STRLOC, g_type_name(type));
809 }
810 break;
811
812 default:
813 g_warning( "%s: unimplemented GType %s",
814 G_STRLOC, g_type_name(fundamental));
815 break;
816 }
817
818 return 0;
819 }
820
821 static int
vips_php_get_value(VipsPhpCall * call,GParamSpec * pspec,zval * zvalue)822 vips_php_get_value(VipsPhpCall *call, GParamSpec *pspec, zval *zvalue)
823 {
824 const char *name = g_param_spec_get_name(pspec);
825 GType pspec_type = G_PARAM_SPEC_VALUE_TYPE(pspec);
826 GValue gvalue = { 0 };
827
828 g_value_init(&gvalue, pspec_type);
829 g_object_get_property(G_OBJECT(call->operation), name, &gvalue);
830 if (vips_php_gval_to_zval(&gvalue, zvalue)) {
831 g_value_unset(&gvalue);
832 return -1;
833 }
834
835 #ifdef VIPS_DEBUG
836 {
837 char *str_value;
838
839 str_value = g_strdup_value_contents(&gvalue);
840 VIPS_DEBUG_MSG(" %s.%s = %s\n", call->operation_name, name, str_value);
841 g_free(str_value);
842 }
843 #endif/*VIPS_DEBUG*/
844
845 g_value_unset(&gvalue);
846
847 return 0;
848 }
849
850 static void *
vips_php_get_required_output(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)851 vips_php_get_required_output(VipsObject *object,
852 GParamSpec *pspec, VipsArgumentClass *argument_class,
853 VipsArgumentInstance *argument_instance,
854 void *a, void *b)
855 {
856 VipsPhpCall *call = (VipsPhpCall *) a;
857 zval *return_value = (zval *) b;
858
859 /* We get output objects, and we get input objects that are tagged as
860 * MODIFY --- they are copied on set, see above.
861 */
862 if ((argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
863 (argument_class->flags & (VIPS_ARGUMENT_OUTPUT| VIPS_ARGUMENT_MODIFY)) &&
864 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) {
865 const char *name = g_param_spec_get_name(pspec);
866 zval zvalue;
867
868 if (vips_php_get_value(call, pspec, &zvalue)) {
869 return call;
870 }
871 add_assoc_zval(return_value, name, &zvalue);
872 }
873
874 return NULL;
875 }
876
877 static int
vips_php_get_optional_output(VipsPhpCall * call,zval * options,zval * return_value)878 vips_php_get_optional_output(VipsPhpCall *call, zval *options,
879 zval *return_value)
880 {
881 zend_string *key;
882 zval *value;
883
884 VIPS_DEBUG_MSG("vips_php_get_optional_output:\n");
885
886 options = zval_get_nonref(options);
887
888 ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), key, value) {
889 char *name;
890 GParamSpec *pspec;
891 VipsArgumentClass *argument_class;
892 VipsArgumentInstance *argument_instance;
893
894 if (key == NULL) {
895 continue;
896 }
897
898 /* value should always be TRUE.
899 */
900 value = zval_get_nonref(value);
901 if (Z_TYPE_P(value) != IS_TRUE) {
902 continue;
903 }
904
905 name = ZSTR_VAL(key);
906 if (vips_object_get_argument(VIPS_OBJECT(call->operation), name,
907 &pspec, &argument_class, &argument_instance)) {
908 return -1;
909 }
910
911 if (!(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
912 (argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
913 !(argument_class->flags & VIPS_ARGUMENT_DEPRECATED)) {
914 zval zvalue;
915
916 if (vips_php_get_value(call, pspec, &zvalue)) {
917 return -1;
918 }
919
920 add_assoc_zval(return_value, name, &zvalue);
921 }
922 } ZEND_HASH_FOREACH_END();
923
924 return 0;
925 }
926
927 /* Call any vips operation, with the arguments coming from an array of zval.
928 * argv can have an extra final arg, which is an associative array of
929 * optional arguments.
930 */
931 static int
vips_php_call_array(const char * operation_name,zval * instance,const char * option_string,int argc,zval * argv,zval * return_value)932 vips_php_call_array(const char *operation_name, zval *instance,
933 const char *option_string, int argc, zval *argv, zval *return_value)
934 {
935 VipsPhpCall *call;
936 int i;
937
938 VIPS_DEBUG_MSG("vips_php_call_array:\n");
939
940 if (!(call = vips_php_call_new(operation_name, instance, option_string,
941 argc, argv))) {
942 return -1;
943 }
944
945 /* Some initial analysis of our args. Loop over them all, including the
946 * special 'instance' arg.
947 */
948 VIPS_DEBUG_MSG("vips_php_call_array: analyzing input args ...\n");
949 if (call->instance) {
950 vips_php_analyze_arg(call, call->instance);
951 }
952 for (i = 0; i < argc; i++) {
953 vips_php_analyze_arg(call, &call->argv[i]);
954 }
955
956 /* Set str options before vargs options, so the user can't
957 * override things we set deliberately.
958 */
959 VIPS_DEBUG_MSG("vips_php_call_array: setting args from option_string ...\n");
960 if (option_string &&
961 vips_object_set_from_string(VIPS_OBJECT(call->operation),
962 option_string)) {
963 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
964 vips_php_call_free(call);
965 return -1;
966 }
967
968 /* Set all required input args from argv.
969 */
970 VIPS_DEBUG_MSG("vips_php_call_array: setting required input args ...\n");
971 if (vips_argument_map(VIPS_OBJECT(call->operation),
972 vips_php_set_required_input, call, NULL)) {
973 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
974 vips_php_call_free(call);
975 return -1;
976 }
977
978 /* args_required must match argc, or we allow one extra final arg for options.
979 */
980 VIPS_DEBUG_MSG("vips_php_call_array: testing argc ...\n");
981 if (call->argc == call->args_required + 1) {
982 /* Make sure it really is an array.
983 */
984 if (zend_parse_parameter(0, call->argc - 1, &call->argv[call->argc - 1],
985 "a", &call->options) == FAILURE) {
986 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
987 vips_php_call_free(call);
988 return -1;
989 }
990 }
991 else if (call->argc != call->args_required) {
992 php_error_docref(NULL, E_WARNING,
993 "operation %s expects %d arguments, but you supplied %d",
994 call->operation_name, call->args_required, call->argc);
995 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
996 vips_php_call_free(call);
997 return -1;
998 }
999
1000 /* Set all optional arguments.
1001 */
1002 VIPS_DEBUG_MSG("vips_php_call_array: setting optional input args ...\n");
1003 if (call->options &&
1004 vips_php_set_optional_input(call, call->options)) {
1005 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
1006 vips_php_call_free(call);
1007 return -1;
1008 }
1009
1010 /* Look up in cache and build.
1011 */
1012 VIPS_DEBUG_MSG("vips_php_call_array: building ...\n");
1013 if (vips_cache_operation_buildp(&call->operation)) {
1014 VIPS_DEBUG_MSG("vips_php_call_array: call failed!\n");
1015 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
1016 vips_php_call_free(call);
1017 return -1;
1018 }
1019
1020 /* Walk args again, getting required output.
1021 */
1022 VIPS_DEBUG_MSG("vips_php_call_array: getting required output ...\n");
1023 array_init(return_value);
1024 if (vips_argument_map(VIPS_OBJECT(call->operation),
1025 vips_php_get_required_output, call, return_value)) {
1026 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
1027 vips_php_call_free(call);
1028 return -1;
1029 }
1030
1031 /* And optional output.
1032 */
1033 VIPS_DEBUG_MSG("vips_php_call_array: getting optional output ...\n");
1034 if (call->options &&
1035 vips_php_get_optional_output(call, call->options, return_value)) {
1036 vips_object_unref_outputs(VIPS_OBJECT(call->operation));
1037 vips_php_call_free(call);
1038 return -1;
1039 }
1040
1041 vips_php_call_free(call);
1042
1043 VIPS_DEBUG_MSG("vips_php_call_array: success!\n");
1044
1045 return 0;
1046 }
1047
1048 /* }}} */
1049
1050 /* {{{ proto mixed vips_php_call(string operation_name, resource instance [, more])
1051 Call any vips operation */
1052
PHP_FUNCTION(vips_call)1053 PHP_FUNCTION(vips_call)
1054 {
1055 int argc;
1056 zval *argv;
1057 char *operation_name;
1058 size_t operation_name_len;
1059 zval *instance;
1060
1061 VIPS_DEBUG_MSG("vips_call:\n");
1062
1063 argc = ZEND_NUM_ARGS();
1064
1065 if (argc < 1) {
1066 WRONG_PARAM_COUNT;
1067 }
1068
1069 argv = (zval *)emalloc(argc * sizeof(zval));
1070
1071 if (zend_get_parameters_array_ex(argc, argv) == FAILURE) {
1072 efree(argv);
1073 WRONG_PARAM_COUNT;
1074 }
1075
1076 if (zend_parse_parameter(0, 0, &argv[0],
1077 "s", &operation_name, &operation_name_len) == FAILURE) {
1078 efree(argv);
1079 RETURN_LONG(-1);
1080 }
1081
1082 if (zend_parse_parameter(0, 1, &argv[1], "r!", &instance) == FAILURE) {
1083 efree(argv);
1084 RETURN_LONG(-1);
1085 }
1086
1087 if (vips_php_call_array(operation_name, instance,
1088 "", argc - 2, argv + 2, return_value)) {
1089 efree(argv);
1090 RETURN_LONG(-1);
1091 }
1092
1093 efree(argv);
1094 }
1095 /* }}} */
1096
1097 /* {{{ proto resource vips_image_new_from_file(string filename [, array options])
1098 Open an image from a filename */
PHP_FUNCTION(vips_image_new_from_file)1099 PHP_FUNCTION(vips_image_new_from_file)
1100 {
1101 char *name;
1102 size_t name_len;
1103 zval *options;
1104 char filename[VIPS_PATH_MAX];
1105 char option_string[VIPS_PATH_MAX];
1106 const char *operation_name;
1107 zval argv[2];
1108 int argc;
1109
1110 VIPS_DEBUG_MSG("vips_image_new_from_file:\n");
1111
1112 options = NULL;
1113 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|a",
1114 &name, &name_len, &options) == FAILURE) {
1115 RETURN_LONG(-1);
1116 }
1117 VIPS_DEBUG_MSG("vips_image_new_from_file: name = %s\n", name);
1118
1119 vips__filename_split8(name, filename, option_string);
1120 if (!(operation_name = vips_foreign_find_load(filename))) {
1121 RETURN_LONG(-1);
1122 }
1123
1124 ZVAL_STRING(&argv[0], filename);
1125 argc = 1;
1126 if (options) {
1127 ZVAL_ARR(&argv[1], Z_ARR_P(options));
1128 argc += 1;
1129 }
1130
1131 if (vips_php_call_array(operation_name, NULL,
1132 option_string, argc, argv, return_value)) {
1133 zval_dtor(&argv[0]);
1134 RETURN_LONG(-1);
1135 }
1136
1137 zval_dtor(&argv[0]);
1138 }
1139 /* }}} */
1140
1141 /* {{{ proto resource vips_image_new_from_buffer(string buffer [, string option_string, array options])
1142 Open an image from a string */
PHP_FUNCTION(vips_image_new_from_buffer)1143 PHP_FUNCTION(vips_image_new_from_buffer)
1144 {
1145 char *buffer;
1146 size_t buffer_len;
1147 char *option_string;
1148 size_t option_string_len;
1149 zval *options;
1150 const char *operation_name;
1151 zval argv[2];
1152 int argc;
1153
1154 VIPS_DEBUG_MSG("vips_image_new_from_buffer:\n");
1155
1156 option_string = NULL;
1157 options = NULL;
1158 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|sa",
1159 &buffer, &buffer_len, &option_string, &option_string_len,
1160 &options) == FAILURE) {
1161 RETURN_LONG(-1);
1162 }
1163
1164 if (!(operation_name = vips_foreign_find_load_buffer(buffer, buffer_len))) {
1165 RETURN_LONG(-1);
1166 }
1167
1168 ZVAL_STRINGL(&argv[0], buffer, buffer_len);
1169 argc = 1;
1170 if (options) {
1171 ZVAL_ARR(&argv[1], Z_ARR_P(options));
1172 argc += 1;
1173 }
1174
1175 if (vips_php_call_array(operation_name, NULL,
1176 option_string, argc, argv, return_value)) {
1177 zval_dtor(&argv[0]);
1178 RETURN_LONG(-1);
1179 }
1180
1181 zval_dtor(&argv[0]);
1182 }
1183 /* }}} */
1184
1185 /* {{{ proto resource vips_image_new_from_array(array coefficients [, double scale, double offset])
1186 Open an image from a string */
PHP_FUNCTION(vips_image_new_from_array)1187 PHP_FUNCTION(vips_image_new_from_array)
1188 {
1189 zval *array;
1190 double scale;
1191 double offset;
1192 int width;
1193 int height;
1194 VipsImage *mat;
1195 int x;
1196 zval *row;
1197
1198 VIPS_DEBUG_MSG("vips_image_new_from_array:\n");
1199
1200 scale = 1.0;
1201 offset = 0.0;
1202 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|dd",
1203 &array, &scale, &offset) == FAILURE) {
1204 return;
1205 }
1206
1207 height = zend_hash_num_elements(Z_ARRVAL_P(array));
1208 if ((row = zend_hash_index_find(Z_ARRVAL_P(array), 0)) == NULL) {
1209 php_error_docref(NULL, E_WARNING, "no element zero");
1210 return;
1211 }
1212 if (is_2D(array)) {
1213 mat = matrix_from_zval(array);
1214 }
1215 else {
1216 /* 1D array.
1217 */
1218 width = height;
1219 height = 1;
1220
1221 mat = vips_image_new_matrix(width, height);
1222
1223 for (x = 0; x < width; x++) {
1224 zval *ele;
1225
1226 ele = zend_hash_index_find(Z_ARRVAL_P(array), x);
1227 if (ele) {
1228 *VIPS_MATRIX(mat, x, 0) = zval_get_double(ele);
1229 }
1230 }
1231 }
1232
1233 vips_image_set_double(mat, "scale", scale);
1234 vips_image_set_double(mat, "offset", offset);
1235
1236 RETURN_RES(zend_register_resource(mat, le_gobject));
1237 }
1238 /* }}} */
1239
1240 /* {{{ proto resource vips_interpolate_new(string name])
1241 make a new interpolator */
PHP_FUNCTION(vips_interpolate_new)1242 PHP_FUNCTION(vips_interpolate_new)
1243 {
1244 char *name;
1245 size_t name_len;
1246 VipsInterpolate *interp;
1247
1248 VIPS_DEBUG_MSG("vips_interpolate_new:\n");
1249
1250 if (zend_parse_parameters(ZEND_NUM_ARGS(), "p",
1251 &name, &name_len) == FAILURE) {
1252 return;
1253 }
1254 VIPS_DEBUG_MSG("vips_interpolate_new: name = %s\n", name);
1255
1256 if (!(interp = vips_interpolate_new(name)))
1257 return;
1258
1259 RETURN_RES(zend_register_resource(interp, le_gobject));
1260 }
1261 /* }}} */
1262
1263 /* {{{ proto long vips_image_write_to_file(resource image, string filename [, array options])
1264 Write an image to a filename */
PHP_FUNCTION(vips_image_write_to_file)1265 PHP_FUNCTION(vips_image_write_to_file)
1266 {
1267 zval *IM;
1268 char *filename;
1269 size_t filename_len;
1270 zval *options = NULL;
1271 VipsImage *image;
1272 char path_string[VIPS_PATH_MAX];
1273 char option_string[VIPS_PATH_MAX];
1274 const char *operation_name;
1275 zval argv[2];
1276 int argc;
1277
1278 VIPS_DEBUG_MSG("vips_image_write_to_file:\n");
1279
1280 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rp|a",
1281 &IM, &filename, &filename_len, &options) == FAILURE) {
1282 RETURN_LONG(-1);
1283 }
1284
1285 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(IM),
1286 "GObject", le_gobject)) == NULL) {
1287 RETURN_LONG(-1);
1288 }
1289
1290 VIPS_DEBUG_MSG("\t%p -> %s\n", image, filename);
1291
1292 vips__filename_split8(filename, path_string, option_string);
1293 if (!(operation_name = vips_foreign_find_save(path_string))) {
1294 RETURN_LONG(-1);
1295 }
1296
1297 ZVAL_STRINGL(&argv[0], filename, filename_len);
1298 argc = 1;
1299 if (options) {
1300 ZVAL_ARR(&argv[1], Z_ARR_P(options));
1301 argc += 1;
1302 }
1303
1304 if (vips_php_call_array(operation_name, IM,
1305 option_string, argc, argv, return_value)) {
1306 zval_dtor(&argv[0]);
1307 RETURN_LONG(-1);
1308 }
1309
1310 zval_dtor(&argv[0]);
1311 }
1312 /* }}} */
1313
1314 /* {{{ proto string|long vips_image_write_to_buffer(resource image, string suffix [, array options])
1315 Write an image to a string */
PHP_FUNCTION(vips_image_write_to_buffer)1316 PHP_FUNCTION(vips_image_write_to_buffer)
1317 {
1318 zval *IM;
1319 zval *options = NULL;
1320 char *suffix;
1321 size_t suffix_len;
1322 VipsImage *image;
1323 char filename[VIPS_PATH_MAX];
1324 char option_string[VIPS_PATH_MAX];
1325 const char *operation_name;
1326 zval argv[1];
1327 int argc;
1328
1329 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|a",
1330 &IM, &suffix, &suffix_len, &options) == FAILURE) {
1331 RETURN_LONG(-1);
1332 }
1333
1334 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(IM),
1335 "GObject", le_gobject)) == NULL) {
1336 RETURN_LONG(-1);
1337 }
1338
1339 vips__filename_split8(suffix, filename, option_string);
1340 if (!(operation_name = vips_foreign_find_save_buffer(filename))) {
1341 RETURN_LONG(-1);
1342 }
1343
1344 argc = 0;
1345 if (options) {
1346 ZVAL_ARR(&argv[0], Z_ARR_P(options));
1347 argc += 1;
1348 }
1349
1350 if (vips_php_call_array(operation_name, IM,
1351 option_string, argc, argv, return_value)) {
1352 RETURN_LONG(-1);
1353 }
1354 }
1355 /* }}} */
1356
1357 /* {{{ proto resource vips_image_copy_memory(resource image)
1358 Copy an image to a memory image */
PHP_FUNCTION(vips_image_copy_memory)1359 PHP_FUNCTION(vips_image_copy_memory)
1360 {
1361 zval *IM;
1362 VipsImage *image;
1363 VipsImage *new_image;
1364 zend_resource *resource;
1365 zval zvalue;
1366
1367 VIPS_DEBUG_MSG("vips_image_copy_memory:\n");
1368
1369 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &IM) == FAILURE) {
1370 RETURN_LONG(-1);
1371 }
1372
1373 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(IM),
1374 "GObject", le_gobject)) == NULL) {
1375 RETURN_LONG(-1);
1376 }
1377
1378 if (!(new_image = vips_image_copy_memory(image))) {
1379 RETURN_LONG(-1);
1380 }
1381
1382 /* Return as an array for all OK, -1 for error.
1383 */
1384 array_init(return_value);
1385 resource = zend_register_resource(new_image, le_gobject);
1386 ZVAL_RES(&zvalue, resource);
1387 add_assoc_zval(return_value, "out", &zvalue);
1388 }
1389 /* }}} */
1390
1391 /* {{{ proto resource vips_image_new_from_memory(string data, integer width, integer height, integer bands, string format)
1392 Wrap an image around a memory array. */
PHP_FUNCTION(vips_image_new_from_memory)1393 PHP_FUNCTION(vips_image_new_from_memory)
1394 {
1395 char *bstr;
1396 size_t bstr_len;
1397 long width;
1398 long height;
1399 long bands;
1400 char *format;
1401 size_t format_len;
1402 int format_value;
1403 VipsBandFormat band_format;
1404 VipsImage *image;
1405 zend_resource *resource;
1406 zval zvalue;
1407
1408 VIPS_DEBUG_MSG("vips_image_new_from_memory:\n");
1409
1410 if (zend_parse_parameters(ZEND_NUM_ARGS(), "slllp",
1411 &bstr, &bstr_len, &width, &height, &bands, &format, &format_len) == FAILURE) {
1412 RETURN_LONG(-1);
1413 }
1414
1415 if ((format_value = vips_enum_from_nick("php-vips", VIPS_TYPE_BAND_FORMAT, format)) < 0) {
1416 RETURN_LONG(-1);
1417 }
1418 band_format = format_value;
1419
1420 if (!(image = vips_image_new_from_memory_copy(bstr, bstr_len, width, height, bands,
1421 band_format))) {
1422 RETURN_LONG(-1);
1423 }
1424
1425 /* Return as an array for all OK, -1 for error.
1426 */
1427 array_init(return_value);
1428 resource = zend_register_resource(image, le_gobject);
1429 ZVAL_RES(&zvalue, resource);
1430 add_assoc_zval(return_value, "out", &zvalue);
1431 }
1432 /* }}} */
1433
1434 /* {{{ proto string vips_image_write_to_memory(resource image)
1435 Write an image to a memory array. */
PHP_FUNCTION(vips_image_write_to_memory)1436 PHP_FUNCTION(vips_image_write_to_memory)
1437 {
1438 zval *IM;
1439 VipsImage *image;
1440 size_t arr_len;
1441 uint8_t *arr;
1442
1443 VIPS_DEBUG_MSG("vips_image_write_to_memory:\n");
1444
1445 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &IM) == FAILURE) {
1446 RETURN_LONG(-1);
1447 }
1448
1449 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(IM),
1450 "GObject", le_gobject)) == NULL) {
1451 RETURN_LONG(-1);
1452 }
1453
1454 if (!(arr = vips_image_write_to_memory(image, &arr_len))) {
1455 RETURN_LONG(-1);
1456 }
1457
1458 RETVAL_STRINGL((char *)arr, arr_len);
1459
1460 g_free(arr);
1461 }
1462 /* }}} */
1463
1464 #define ADD_ELEMENTS(TYPE, APPEND, N) { \
1465 TYPE *p = (TYPE *) arr; \
1466 size_t i; \
1467 \
1468 for (i = 0; i < (N); i++) \
1469 APPEND(return_value, p[i]); \
1470 }
1471
1472 /* {{{ proto array vips_image_write_to_array(resource image)
1473 Write an image to a PHP array. */
PHP_FUNCTION(vips_image_write_to_array)1474 PHP_FUNCTION(vips_image_write_to_array)
1475 {
1476 zval *IM;
1477 VipsImage *image;
1478 size_t arr_len;
1479 uint8_t *arr;
1480 size_t n;
1481
1482 VIPS_DEBUG_MSG("vips_image_write_to_array:\n");
1483
1484 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &IM) == FAILURE) {
1485 RETURN_LONG(-1);
1486 }
1487
1488 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(IM),
1489 "GObject", le_gobject)) == NULL) {
1490 RETURN_LONG(-1);
1491 }
1492
1493 if (!(arr = vips_image_write_to_memory(image, &arr_len))) {
1494 RETURN_LONG(-1);
1495 }
1496
1497 array_init(return_value);
1498 n = arr_len / vips_format_sizeof(image->BandFmt);
1499 g_assert(arr_len % vips_format_sizeof(image->BandFmt) == 0);
1500 switch (image->BandFmt) {
1501 case VIPS_FORMAT_UCHAR:
1502 ADD_ELEMENTS (unsigned char, add_next_index_long, n);
1503 break;
1504
1505 case VIPS_FORMAT_CHAR:
1506 ADD_ELEMENTS (signed char, add_next_index_long, n);
1507 break;
1508
1509 case VIPS_FORMAT_USHORT:
1510 ADD_ELEMENTS (unsigned short, add_next_index_long, n);
1511 break;
1512
1513 case VIPS_FORMAT_SHORT:
1514 ADD_ELEMENTS (signed short, add_next_index_long, n);
1515 break;
1516
1517 case VIPS_FORMAT_UINT:
1518 ADD_ELEMENTS (unsigned int, add_next_index_long, n);
1519 break;
1520
1521 case VIPS_FORMAT_INT:
1522 ADD_ELEMENTS (signed int, add_next_index_long, n);
1523 break;
1524
1525 case VIPS_FORMAT_FLOAT:
1526 ADD_ELEMENTS (float, add_next_index_double, n);
1527 break;
1528
1529 case VIPS_FORMAT_DOUBLE:
1530 ADD_ELEMENTS (double, add_next_index_double, n);
1531 break;
1532
1533 case VIPS_FORMAT_COMPLEX:
1534 ADD_ELEMENTS (float, add_next_index_double, n * 2);
1535 break;
1536
1537 case VIPS_FORMAT_DPCOMPLEX:
1538 ADD_ELEMENTS (double, add_next_index_double, n * 2);
1539 break;
1540
1541 default:
1542 break;
1543 }
1544
1545 g_free(arr);
1546 }
1547 /* }}} */
1548
1549 /* {{{ proto string|long vips_foreign_find_load(string filename)
1550 Find a loader for a file */
PHP_FUNCTION(vips_foreign_find_load)1551 PHP_FUNCTION(vips_foreign_find_load)
1552 {
1553 char *filename;
1554 size_t filename_len;
1555 const char *operation_name;
1556
1557 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1558 &filename, &filename_len) == FAILURE) {
1559 RETURN_LONG(-1);
1560 }
1561
1562 if (!(operation_name = vips_foreign_find_load(filename))) {
1563 RETURN_LONG(-1);
1564 }
1565
1566 RETVAL_STRING(strdup(operation_name));
1567 }
1568 /* }}} */
1569
1570 /* {{{ proto string|long vips_foreign_find_load_buffer(string buffer)
1571 Find a loader for a buffer */
PHP_FUNCTION(vips_foreign_find_load_buffer)1572 PHP_FUNCTION(vips_foreign_find_load_buffer)
1573 {
1574 char *buffer;
1575 size_t buffer_len;
1576 const char *operation_name;
1577
1578 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s",
1579 &buffer, &buffer_len) == FAILURE) {
1580 RETURN_LONG(-1);
1581 }
1582
1583 if (!(operation_name = vips_foreign_find_load_buffer(buffer, buffer_len))) {
1584 RETURN_LONG(-1);
1585 }
1586
1587 RETVAL_STRING(strdup(operation_name));
1588 }
1589 /* }}} */
1590
1591 /* {{{ proto array vips_image_get(resource image, string field)
1592 Fetch field from image */
PHP_FUNCTION(vips_image_get)1593 PHP_FUNCTION(vips_image_get)
1594 {
1595 zval *im;
1596 char *field_name;
1597 size_t field_name_len;
1598 VipsImage *image;
1599 GValue gvalue = { 0 };
1600 zval zvalue;
1601 GParamSpec *pspec;
1602
1603 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs",
1604 &im, &field_name, &field_name_len) == FAILURE) {
1605 RETURN_LONG(-1);
1606 }
1607
1608 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(im),
1609 "GObject", le_gobject)) == NULL) {
1610 RETURN_LONG(-1);
1611 }
1612
1613 /* Ugly: older libvipses would return enums from the true header fields
1614 * (eg. ->interpretation) as ints, but we want to send a string back
1615 * for things like this.
1616 *
1617 * Test if field_name exists as a regular glib property and if it does, use
1618 * g_object_get(). Otherwise use vips_image_get(), since it can read extra
1619 * image metadata.
1620 */
1621 if ((pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(image),
1622 field_name))) {
1623 g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec));
1624 g_object_get_property(G_OBJECT(image), field_name, &gvalue);
1625 }
1626 else if (vips_image_get(image, field_name, &gvalue)) {
1627 RETURN_LONG(-1);
1628 }
1629
1630 if (vips_php_gval_to_zval(&gvalue, &zvalue)) {
1631 g_value_unset(&gvalue);
1632 RETURN_LONG(-1);
1633 }
1634 g_value_unset(&gvalue);
1635
1636 /* Return as an array for all OK, -1 for error.
1637 */
1638 array_init(return_value);
1639 add_assoc_zval(return_value, "out", &zvalue);
1640 }
1641 /* }}} */
1642
1643 /* {{{ proto long vips_image_get_typeof(resource image, string field)
1644 Fetch type of field from image */
PHP_FUNCTION(vips_image_get_typeof)1645 PHP_FUNCTION(vips_image_get_typeof)
1646 {
1647 zval *im;
1648 char *field_name;
1649 size_t field_name_len;
1650 VipsImage *image;
1651 GType type;
1652
1653 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs",
1654 &im, &field_name, &field_name_len) == FAILURE) {
1655 RETURN_LONG(-1);
1656 }
1657
1658 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(im),
1659 "GObject", le_gobject)) == NULL) {
1660 RETURN_LONG(-1);
1661 }
1662
1663 type = vips_image_get_typeof(image, field_name);
1664
1665 RETURN_LONG(type);
1666 }
1667 /* }}} */
1668
1669 /* {{{ proto long vips_image_set(resource image, string field, mixed value)
1670 Set field on image */
PHP_FUNCTION(vips_image_set)1671 PHP_FUNCTION(vips_image_set)
1672 {
1673 zval *im;
1674 char *field_name;
1675 size_t field_name_len;
1676 zval *zvalue;
1677 VipsImage *image;
1678 GType type;
1679 GValue gvalue = { 0 };
1680
1681 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz",
1682 &im, &field_name, &field_name_len, &zvalue) == FAILURE) {
1683 RETURN_LONG(-1);
1684 }
1685
1686 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(im),
1687 "GObject", le_gobject)) == NULL) {
1688 RETURN_LONG(-1);
1689 }
1690
1691 type = vips_image_get_typeof(image, field_name);
1692
1693 /* If the type is not set, guess a default.
1694 */
1695 if (type == 0) {
1696 zval *ele;
1697
1698 type = 0;
1699
1700 zvalue = zval_get_nonref(zvalue);
1701
1702 switch (Z_TYPE_P(zvalue)) {
1703 case IS_ARRAY:
1704 if ((ele = zend_hash_index_find(Z_ARRVAL_P(zvalue),
1705 0)) != NULL) {
1706 ele = zval_get_nonref(ele);
1707
1708 switch (Z_TYPE_P(ele)) {
1709 case IS_RESOURCE:
1710 type = VIPS_TYPE_ARRAY_IMAGE;
1711 break;
1712
1713 case IS_LONG:
1714 type = VIPS_TYPE_ARRAY_INT;
1715 break;
1716
1717 case IS_DOUBLE:
1718 type = VIPS_TYPE_ARRAY_DOUBLE;
1719 break;
1720
1721 default:
1722 break;
1723 }
1724 }
1725 break;
1726
1727 case IS_RESOURCE:
1728 type = VIPS_TYPE_IMAGE;
1729 break;
1730
1731 case IS_LONG:
1732 type = G_TYPE_INT;
1733 break;
1734
1735 case IS_DOUBLE:
1736 type = G_TYPE_DOUBLE;
1737 break;
1738
1739 case IS_STRING:
1740 type = VIPS_TYPE_REF_STRING;
1741 break;
1742
1743 default:
1744 break;
1745 }
1746 }
1747
1748 g_value_init(&gvalue, type);
1749
1750 if (vips_php_zval_to_gval(NULL, zvalue, &gvalue)) {
1751 RETURN_LONG(-1);
1752 }
1753
1754 vips_image_set(image, field_name, &gvalue);
1755
1756 g_value_unset(&gvalue);
1757
1758 RETURN_LONG(0);
1759 }
1760 /* }}} */
1761
1762 /* {{{ proto long vips_image_remove(resource image, string field)
1763 Remove field from image */
PHP_FUNCTION(vips_image_remove)1764 PHP_FUNCTION(vips_image_remove)
1765 {
1766 zval *im;
1767 char *field_name;
1768 size_t field_name_len;
1769 VipsImage *image;
1770
1771 if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs",
1772 &im, &field_name, &field_name_len) == FAILURE) {
1773 RETURN_LONG(-1);
1774 }
1775
1776 if ((image = (VipsImage *)zend_fetch_resource(Z_RES_P(im),
1777 "GObject", le_gobject)) == NULL) {
1778 RETURN_LONG(-1);
1779 }
1780
1781 if (!vips_image_remove(image, field_name)) {
1782 RETURN_LONG(-1);
1783 }
1784
1785 RETURN_LONG(0);
1786 }
1787 /* }}} */
1788
1789 /* {{{ proto string vips_error_buffer()
1790 Fetch and clear the vips error buffer */
PHP_FUNCTION(vips_error_buffer)1791 PHP_FUNCTION(vips_error_buffer)
1792 {
1793 if (zend_parse_parameters(ZEND_NUM_ARGS(), "") == FAILURE) {
1794 return;
1795 }
1796
1797 RETVAL_STRING(strdup(vips_error_buffer()));
1798 vips_error_clear();
1799 }
1800 /* }}} */
1801
1802 /* {{{ proto void vips_cache_set_max(integer value)
1803 Set max number of operations to cache */
PHP_FUNCTION(vips_cache_set_max)1804 PHP_FUNCTION(vips_cache_set_max)
1805 {
1806 long value;
1807
1808 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
1809 return;
1810 }
1811
1812 vips_cache_set_max(value);
1813 }
1814 /* }}} */
1815
1816 /* {{{ proto void vips_cache_set_max_mem(integer value)
1817 Set max memory to use for operation cache */
PHP_FUNCTION(vips_cache_set_max_mem)1818 PHP_FUNCTION(vips_cache_set_max_mem)
1819 {
1820 long value;
1821
1822 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
1823 return;
1824 }
1825
1826 vips_cache_set_max_mem(value);
1827 }
1828 /* }}} */
1829
1830 /* {{{ proto void vips_cache_set_max_files(integer value)
1831 Set max number of open files for operation cache */
PHP_FUNCTION(vips_cache_set_max_files)1832 PHP_FUNCTION(vips_cache_set_max_files)
1833 {
1834 long value;
1835
1836 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
1837 return;
1838 }
1839
1840 vips_cache_set_max_files(value);
1841 }
1842 /* }}} */
1843
1844 /* {{{ proto void vips_concurrency_set(integer value)
1845 Set number of workers per threadpool */
PHP_FUNCTION(vips_concurrency_set)1846 PHP_FUNCTION(vips_concurrency_set)
1847 {
1848 long value;
1849
1850 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &value) == FAILURE) {
1851 return;
1852 }
1853
1854 vips_concurrency_set(value);
1855 }
1856 /* }}} */
1857
1858 /* {{{ proto string vips_version()
1859 Returns the version number of the vips library */
PHP_FUNCTION(vips_version)1860 PHP_FUNCTION(vips_version)
1861 {
1862 char digits[256];
1863
1864 vips_snprintf(digits, 256, "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
1865
1866 RETVAL_STRING(digits);
1867 }
1868 /* }}} */
1869
1870 /* {{{ proto integer vips_cache_get_max_mem()
1871 Get max memory to use for operation cache */
PHP_FUNCTION(vips_cache_get_max_mem)1872 PHP_FUNCTION(vips_cache_get_max_mem)
1873 {
1874 RETURN_LONG(vips_cache_get_max_mem());
1875 }
1876 /* }}} */
1877
1878 /* {{{ proto integer vips_cache_get_max_files()
1879 Get max number of open files for operation cache */
PHP_FUNCTION(vips_cache_get_max_files)1880 PHP_FUNCTION(vips_cache_get_max_files)
1881 {
1882 RETURN_LONG(vips_cache_get_max_files());
1883 }
1884 /* }}} */
1885
1886 /* {{{ proto integer vips_cache_get_max()
1887 Get max number of operations to cache */
PHP_FUNCTION(vips_cache_get_max)1888 PHP_FUNCTION(vips_cache_get_max)
1889 {
1890 RETURN_LONG(vips_cache_get_max());
1891 }
1892 /* }}} */
1893
1894 /* {{{ proto integer vips_cache_get_size()
1895 Get current cached operations */
PHP_FUNCTION(vips_cache_get_size)1896 PHP_FUNCTION(vips_cache_get_size)
1897 {
1898 RETURN_LONG(vips_cache_get_size());
1899 }
1900 /* }}} */
1901
1902 /* {{{ proto integer vips_concurrency_get()
1903 Get number of workers per threadpool */
PHP_FUNCTION(vips_concurrency_get)1904 PHP_FUNCTION(vips_concurrency_get)
1905 {
1906 RETURN_LONG(vips_concurrency_get());
1907 }
1908 /* }}} */
1909
1910 /* {{{ php_vips_init_globals
1911 */
1912 /* Uncomment this function if you have INI entries
1913 static void php_vips_init_globals(zend_vips_globals *vips_globals)
1914 {
1915 vips_globals->global_value = 0;
1916 vips_globals->global_string = NULL;
1917 }
1918 */
1919 /* }}} */
1920
1921 /* {{{ php_free_vips_object
1922 * */
php_free_gobject(zend_resource * rsrc)1923 static void php_free_gobject(zend_resource *rsrc)
1924 {
1925 VIPS_DEBUG_MSG("php_free_gobject: %p\n", rsrc->ptr);
1926
1927 g_object_unref((GObject *) rsrc->ptr);
1928 }
1929 /* }}} */
1930
1931 /* {{{ PHP_MINIT_FUNCTION
1932 */
PHP_MINIT_FUNCTION(vips)1933 PHP_MINIT_FUNCTION(vips)
1934 {
1935 if (strcmp(sapi_module.name, "apache2handler") == 0) {
1936 /* "apachectl graceful" can cause us terrible problems. What happens:
1937 *
1938 * - the main apache process unloads this extension, vips.so
1939 * - in turn, the C runtime will unload libvips.so, the vips library,
1940 * since vips.so is the only thing that references it
1941 * - libvips.so in turn uses glib.so, but this is often not unloaded,
1942 * since other parts of apache can be using it (glib could also
1943 * possibly be preventing unload itself, I'm not sure)
1944 * - the main apache process then reloads vips.so, which in turn will
1945 * reload libvips.so as it starts up
1946 * - vips.so tries to init libvips.so
1947 * - libvips.so tries to register its types (such as VipsImage) with
1948 * glib.so, but finds the types from the previous init still there
1949 * - everything breaks
1950 *
1951 * A simple fix that will always work is just to lock libvips in
1952 * memory and prevent unload. We intentionally leak refs to the shared
1953 * library.
1954 *
1955 * We include the binary API version number that this extension needs.
1956 * We can't just load .so, that's only installed with libvips-dev,
1957 * which may not be present at runtime.
1958 */
1959 #ifdef VIPS_SONAME
1960 if (!dlopen(VIPS_SONAME, RTLD_LAZY | RTLD_NODELETE))
1961 #else /*!VIPS_SONAME*/
1962 if (!dlopen("libvips.so.42", RTLD_LAZY | RTLD_NODELETE))
1963 #endif /*VIPS_SONAME*/
1964 {
1965 sapi_module.sapi_error(E_WARNING, "php-vips-ext: unable to lock "
1966 "libvips -- graceful may be unreliable");
1967 }
1968 }
1969
1970 /* If you have INI entries, uncomment these lines
1971 REGISTER_INI_ENTRIES();
1972 */
1973
1974 /* We're supposed to use the filename of something we think is in
1975 * $VIPSHOME/bin, but we don't have that. Use a nonsense name and
1976 * vips_init() will fall back to other techniques for finding data
1977 * files.
1978 */
1979 if (VIPS_INIT("banana"))
1980 return FAILURE;
1981
1982 le_gobject = zend_register_list_destructors_ex(php_free_gobject,
1983 NULL, "GObject", module_number);
1984
1985 #ifdef VIPS_DEBUG
1986 printf( "php-vips-ext init\n" );
1987 printf( "enabling vips leak testing ...\n" );
1988 vips_leak_set( TRUE );
1989 #endif /*VIPS_DEBUG*/
1990
1991 return SUCCESS;
1992 }
1993 /* }}} */
1994
1995 /* {{{ PHP_MSHUTDOWN_FUNCTION
1996 */
PHP_MSHUTDOWN_FUNCTION(vips)1997 PHP_MSHUTDOWN_FUNCTION(vips)
1998 {
1999 /* uncomment this line if you have INI entries
2000 UNREGISTER_INI_ENTRIES();
2001 */
2002
2003 #ifdef VIPS_DEBUG
2004 printf( "php-vips-ext shutdown\n" );
2005 #endif /*VIPS_DEBUG*/
2006
2007 /* We must not call vips_shutdown() since we've locked libvips in memory
2008 * and will need to reuse it if we restart via graceful.
2009 */
2010
2011 return SUCCESS;
2012 }
2013 /* }}} */
2014
2015 /* Remove if there's nothing to do at request start */
2016 /* {{{ PHP_RINIT_FUNCTION
2017 */
PHP_RINIT_FUNCTION(vips)2018 PHP_RINIT_FUNCTION(vips)
2019 {
2020 #if defined(COMPILE_DL_VIPS) && defined(ZTS)
2021 ZEND_TSRMLS_CACHE_UPDATE();
2022 #endif
2023 return SUCCESS;
2024 }
2025 /* }}} */
2026
2027 /* Remove if there's nothing to do at request end */
2028 /* {{{ PHP_RSHUTDOWN_FUNCTION
2029 */
PHP_RSHUTDOWN_FUNCTION(vips)2030 PHP_RSHUTDOWN_FUNCTION(vips)
2031 {
2032 return SUCCESS;
2033 }
2034 /* }}} */
2035
2036 /* {{{ PHP_MINFO_FUNCTION
2037 */
PHP_MINFO_FUNCTION(vips)2038 PHP_MINFO_FUNCTION(vips)
2039 {
2040 char digits[256];
2041
2042 php_info_print_table_start();
2043 php_info_print_table_header(2, "vips property", "value");
2044
2045 vips_snprintf(digits, 256, "%d.%d.%d", VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION);
2046 php_info_print_table_row(2, "Vips headers version", digits);
2047 vips_snprintf(digits, 256, "%d.%d.%d", vips_version(0), vips_version(1), vips_version(2));
2048 php_info_print_table_row(2, "Vips library version", digits);
2049 vips_snprintf(digits, 256, "%d.%d.%d", vips_version(3), vips_version(4), vips_version(5));
2050 php_info_print_table_row(2, "Vips ABI version", digits);
2051
2052 vips_snprintf(digits, 256, "%d", vips_version(0));
2053 php_info_print_table_row(2, "Major version", digits);
2054 vips_snprintf(digits, 256, "%d", vips_version(1));
2055 php_info_print_table_row(2, "Minor version", digits);
2056 vips_snprintf(digits, 256, "%d", vips_version(2));
2057 php_info_print_table_row(2, "Micro version", digits);
2058
2059 vips_snprintf(digits, 256, "%zd", vips_cache_get_max_mem());
2060 php_info_print_table_row(2, "Cache max mem", digits);
2061
2062 vips_snprintf(digits, 256, "%d", vips_cache_get_max());
2063 php_info_print_table_row(2, "Cache max operations", digits);
2064
2065 vips_snprintf(digits, 256, "%d", vips_cache_get_size());
2066 php_info_print_table_row(2, "Cache current operations", digits);
2067
2068 vips_snprintf(digits, 256, "%d", vips_cache_get_max_files());
2069 php_info_print_table_row(2, "Cache max open files", digits);
2070
2071 vips_snprintf(digits, 256, "%d", vips_concurrency_get());
2072 php_info_print_table_row(2, "Concurrency", digits);
2073
2074 php_info_print_table_row(2, "SIMD support with liborc",
2075 vips_vector_isenabled() ? "yes" : "no" );
2076
2077 php_info_print_table_row(2, "JPEG support",
2078 vips_type_find("VipsOperation", "jpegload") ? "yes" : "no" );
2079 php_info_print_table_row(2, "PNG support",
2080 vips_type_find("VipsOperation", "pngload") ? "yes" : "no" );
2081 php_info_print_table_row(2, "TIFF support",
2082 vips_type_find("VipsOperation", "tiffload") ? "yes" : "no" );
2083 php_info_print_table_row(2, "GIF support",
2084 vips_type_find("VipsOperation", "gifload") ? "yes" : "no" );
2085 php_info_print_table_row(2, "OpenEXR support",
2086 vips_type_find("VipsOperation", "openexrload") ? "yes" : "no" );
2087 php_info_print_table_row(2, "load OpenSlide",
2088 vips_type_find("VipsOperation", "openslideload") ? "yes" : "no" );
2089 php_info_print_table_row(2, "load Matlab",
2090 vips_type_find("VipsOperation", "matload") ? "yes" : "no" );
2091 php_info_print_table_row(2, "load PDF",
2092 vips_type_find("VipsOperation", "pdfload") ? "yes" : "no" );
2093 php_info_print_table_row(2, "load SVG",
2094 vips_type_find("VipsOperation", "svgload") ? "yes" : "no" );
2095 php_info_print_table_row(2, "FITS support",
2096 vips_type_find("VipsOperation", "fitsload") ? "yes" : "no" );
2097 php_info_print_table_row(2, "WebP support",
2098 vips_type_find("VipsOperation", "webpload") ? "yes" : "no" );
2099 php_info_print_table_row(2, "HEIF support",
2100 vips_type_find("VipsOperation", "heifload") ? "yes" : "no" );
2101
2102 php_info_print_table_row(2, "load with libMagick",
2103 vips_type_find("VipsOperation", "magickload") ? "yes" : "no" );
2104
2105 php_info_print_table_row(2, "Text rendering support",
2106 vips_type_find("VipsOperation", "text") ? "yes" : "no" );
2107
2108 php_info_print_table_row(2, "ICC profile support with lcms",
2109 vips_icc_present() ? "yes" : "no" );
2110
2111 php_info_print_table_end();
2112
2113 /* Remove comments if you have entries in php.ini
2114 DISPLAY_INI_ENTRIES();
2115 */
2116 }
2117 /* }}} */
2118
2119 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_new_from_file, 0)
2120 ZEND_ARG_INFO(0, filename)
2121 ZEND_ARG_INFO(0, options)
2122 ZEND_END_ARG_INFO()
2123
2124 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_new_from_buffer, 0)
2125 ZEND_ARG_INFO(0, buffer)
2126 ZEND_ARG_INFO(0, option_string)
2127 ZEND_ARG_INFO(0, options)
2128 ZEND_END_ARG_INFO()
2129
2130 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_new_from_array, 0)
2131 ZEND_ARG_INFO(0, array)
2132 ZEND_ARG_INFO(0, scale)
2133 ZEND_ARG_INFO(0, offset)
2134 ZEND_END_ARG_INFO()
2135
2136 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_write_to_file, 0)
2137 ZEND_ARG_INFO(0, image)
2138 ZEND_ARG_INFO(0, filename)
2139 ZEND_ARG_INFO(0, options)
2140 ZEND_END_ARG_INFO()
2141
2142 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_write_to_buffer, 0)
2143 ZEND_ARG_INFO(0, image)
2144 ZEND_ARG_INFO(0, options)
2145 ZEND_END_ARG_INFO()
2146
2147 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_copy_memory, 0)
2148 ZEND_ARG_INFO(0, image)
2149 ZEND_END_ARG_INFO()
2150
2151 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_new_from_memory, 0)
2152 ZEND_ARG_INFO(0, array)
2153 ZEND_ARG_INFO(0, width)
2154 ZEND_ARG_INFO(0, height)
2155 ZEND_ARG_INFO(0, bands)
2156 ZEND_ARG_INFO(0, format)
2157 ZEND_END_ARG_INFO()
2158
2159 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_write_to_memory, 0)
2160 ZEND_ARG_INFO(0, image)
2161 ZEND_END_ARG_INFO()
2162
2163 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_write_to_array, 0)
2164 ZEND_ARG_INFO(0, image)
2165 ZEND_END_ARG_INFO()
2166
2167 ZEND_BEGIN_ARG_INFO(arginfo_vips_foreign_find_load, 0)
2168 ZEND_ARG_INFO(0, filename)
2169 ZEND_END_ARG_INFO()
2170
2171 ZEND_BEGIN_ARG_INFO(arginfo_vips_interpolate_new, 0)
2172 ZEND_ARG_INFO(0, name)
2173 ZEND_END_ARG_INFO()
2174
2175 ZEND_BEGIN_ARG_INFO(arginfo_vips_foreign_find_load_buffer, 0)
2176 ZEND_ARG_INFO(0, buffer)
2177 ZEND_END_ARG_INFO()
2178
2179 ZEND_BEGIN_ARG_INFO(arginfo_vips_call, 0)
2180 ZEND_ARG_INFO(0, operation_name)
2181 ZEND_ARG_INFO(0, instance)
2182 ZEND_END_ARG_INFO()
2183
2184 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_get, 0)
2185 ZEND_ARG_INFO(0, image)
2186 ZEND_ARG_INFO(0, field)
2187 ZEND_END_ARG_INFO()
2188
2189 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_get_typeof, 0)
2190 ZEND_ARG_INFO(0, image)
2191 ZEND_ARG_INFO(0, field)
2192 ZEND_END_ARG_INFO()
2193
2194 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_set, 0)
2195 ZEND_ARG_INFO(0, image)
2196 ZEND_ARG_INFO(0, field)
2197 ZEND_ARG_INFO(0, value)
2198 ZEND_END_ARG_INFO()
2199
2200 ZEND_BEGIN_ARG_INFO(arginfo_vips_image_remove, 0)
2201 ZEND_ARG_INFO(0, image)
2202 ZEND_ARG_INFO(0, field)
2203 ZEND_END_ARG_INFO()
2204
2205 ZEND_BEGIN_ARG_INFO(arginfo_vips_error_buffer, 0)
2206 ZEND_END_ARG_INFO()
2207
2208 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_set_max, 0)
2209 ZEND_ARG_INFO(0, value)
2210 ZEND_END_ARG_INFO()
2211
2212 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_set_max_mem, 0)
2213 ZEND_ARG_INFO(0, value)
2214 ZEND_END_ARG_INFO()
2215
2216 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_set_max_files, 0)
2217 ZEND_ARG_INFO(0, value)
2218 ZEND_END_ARG_INFO()
2219
2220 ZEND_BEGIN_ARG_INFO(arginfo_vips_concurrency_set, 0)
2221 ZEND_ARG_INFO(0, value)
2222 ZEND_END_ARG_INFO()
2223
2224 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_get_max, 0)
2225 ZEND_END_ARG_INFO()
2226
2227 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_get_max_mem, 0)
2228 ZEND_END_ARG_INFO()
2229
2230 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_get_max_files, 0)
2231 ZEND_END_ARG_INFO()
2232
2233 ZEND_BEGIN_ARG_INFO(arginfo_vips_cache_get_size, 0)
2234 ZEND_END_ARG_INFO()
2235
2236 ZEND_BEGIN_ARG_INFO(arginfo_vips_concurrency_get, 0)
2237 ZEND_END_ARG_INFO()
2238
2239 ZEND_BEGIN_ARG_INFO(arginfo_vips_version, 0)
2240 ZEND_END_ARG_INFO()
2241 /* {{{ vips_functions[]
2242 *
2243 * Every user visible function must have an entry in vips_functions[].
2244 */
2245 const zend_function_entry vips_functions[] = {
2246 PHP_FE(vips_image_new_from_file, arginfo_vips_image_new_from_file)
2247 PHP_FE(vips_image_new_from_buffer, arginfo_vips_image_new_from_buffer)
2248 PHP_FE(vips_image_new_from_array, arginfo_vips_image_new_from_array)
2249 PHP_FE(vips_image_write_to_file, arginfo_vips_image_write_to_file)
2250 PHP_FE(vips_image_write_to_buffer, arginfo_vips_image_write_to_buffer)
2251 PHP_FE(vips_image_copy_memory, arginfo_vips_image_copy_memory)
2252 PHP_FE(vips_image_new_from_memory, arginfo_vips_image_new_from_memory)
2253 PHP_FE(vips_image_write_to_memory, arginfo_vips_image_write_to_memory)
2254 PHP_FE(vips_image_write_to_array, arginfo_vips_image_write_to_array)
2255 PHP_FE(vips_foreign_find_load, arginfo_vips_foreign_find_load)
2256 PHP_FE(vips_foreign_find_load_buffer, arginfo_vips_foreign_find_load_buffer)
2257 PHP_FE(vips_interpolate_new, arginfo_vips_interpolate_new)
2258
2259 PHP_FE(vips_call, arginfo_vips_call)
2260 PHP_FE(vips_image_get, arginfo_vips_image_get)
2261 PHP_FE(vips_image_get_typeof, arginfo_vips_image_get_typeof)
2262 PHP_FE(vips_image_set, arginfo_vips_image_set)
2263 PHP_FE(vips_image_remove, arginfo_vips_image_remove)
2264 PHP_FE(vips_error_buffer, arginfo_vips_error_buffer)
2265 PHP_FE(vips_cache_set_max, arginfo_vips_cache_set_max)
2266 PHP_FE(vips_cache_set_max_mem, arginfo_vips_cache_set_max_mem)
2267 PHP_FE(vips_cache_set_max_files, arginfo_vips_cache_set_max_files)
2268 PHP_FE(vips_concurrency_set, arginfo_vips_concurrency_set)
2269 PHP_FE(vips_cache_get_max, arginfo_vips_cache_get_max)
2270 PHP_FE(vips_cache_get_max_mem, arginfo_vips_cache_get_max_mem)
2271 PHP_FE(vips_cache_get_max_files, arginfo_vips_cache_get_max_files)
2272 PHP_FE(vips_cache_get_size, arginfo_vips_cache_get_size)
2273 PHP_FE(vips_concurrency_get, arginfo_vips_concurrency_get)
2274 PHP_FE(vips_version, arginfo_vips_version)
2275
2276 PHP_FE_END /* Must be the last line in vips_functions[] */
2277 };
2278 /* }}} */
2279
2280 /* {{{ vips_module_entry
2281 */
2282 zend_module_entry vips_module_entry = {
2283 STANDARD_MODULE_HEADER,
2284 "vips",
2285 vips_functions,
2286 PHP_MINIT(vips),
2287 PHP_MSHUTDOWN(vips),
2288 PHP_RINIT(vips), /* Replace with NULL if there's nothing to do at request start */
2289 PHP_RSHUTDOWN(vips), /* Replace with NULL if there's nothing to do at request end */
2290 PHP_MINFO(vips),
2291 PHP_VIPS_VERSION,
2292 STANDARD_MODULE_PROPERTIES
2293 };
2294 /* }}} */
2295
2296 #ifdef COMPILE_DL_VIPS
2297 #ifdef ZTS
2298 ZEND_TSRMLS_CACHE_DEFINE()
2299 #endif
2300 ZEND_GET_MODULE(vips)
2301 #endif
2302
2303 /*
2304 * Local variables:
2305 * tab-width: 4
2306 * c-basic-offset: 4
2307 * End:
2308 * vim600: noet sw=4 ts=4 fdm=marker
2309 * vim<600: noet sw=4 ts=4
2310 */
2311