1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 / Imagick |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Dan Ackroyd <danack@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "php_imagick.h"
18 #include "php_imagick_defs.h"
19 #include "php_imagick_macros.h"
20 #include "php_imagick_helpers.h"
21
22 #ifdef IMAGICK_WITH_KERNEL
23
24 #if MagickLibVersion < 0x691
25 // These function defines are required currently as the functions are
26 // currently not available in the public ImageMagick header files
27 // This is being fixed for the next version of ImageMagick.
28 Image
29 *MorphologyApply(const Image *,const ChannelType,const MorphologyMethod,
30 const ssize_t,const KernelInfo *,const CompositeOperator,const double,
31 ExceptionInfo *);
32
33 void
34 ScaleKernelInfo(KernelInfo *,const double,const GeometryFlags),
35 UnityAddKernelInfo(KernelInfo *,const double),
36 ZeroKernelNans(KernelInfo *);
37 #endif
38
39
php_imagickkernelvalues_to_zval(zval * zv,KernelInfo * kernel_info)40 static void php_imagickkernelvalues_to_zval(zval *zv, KernelInfo *kernel_info) {
41 int count;
42 double value;
43 unsigned int x, y;
44 #if PHP_VERSION_ID >= 70000
45 zval row;
46 #else
47 zval *row;
48 #endif
49
50 zval *p_row;
51
52 count = 0;
53
54 for (y=0; y<kernel_info->height ; y++) {
55 #if PHP_VERSION_ID >= 70000
56 p_row = &row;
57 #else
58 MAKE_STD_ZVAL(row);
59 p_row = row;
60 #endif
61
62 array_init(p_row);
63 for (x=0; x<kernel_info->width ; x++) {
64 value = kernel_info->values[count];
65 count++;
66
67 //nan is not equal to itself
68 if (value != value) {
69 //this will be broken by some compilers - need to investigate more...
70 add_next_index_bool(p_row, 0);
71 }
72 else {
73 add_next_index_double(p_row, value);
74 }
75 }
76
77 add_next_index_zval(zv, p_row);
78 }
79 }
80
81
82 #if PHP_VERSION_ID >= 80000
php_imagickkernel_get_debug_info(zend_object * obj,int * is_temp TSRMLS_DC)83 HashTable* php_imagickkernel_get_debug_info(zend_object *obj, int *is_temp TSRMLS_DC) /* {{{ */
84 #else
85 HashTable* php_imagickkernel_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
86 #endif
87 {
88 php_imagickkernel_object *internp;
89 HashTable *debug_info;
90 KernelInfo *kernel_info;
91 #if PHP_VERSION_ID >= 70000
92 zval matrix;
93 #else
94 zval *matrix;
95 #endif
96
97 *is_temp = 1; //var_dump will destroy the hashtable
98
99 #if PHP_VERSION_ID >= 80000
100 internp = php_imagickkernel_fetch_object(obj);
101 #else
102 internp = Z_IMAGICKKERNEL_P(obj);
103 #endif
104 kernel_info = internp->kernel_info;
105
106 ALLOC_HASHTABLE(debug_info);
107 ZEND_INIT_SYMTABLE_EX(debug_info, 1, 0);
108
109 while (kernel_info != NULL) {
110 #if PHP_VERSION_ID >= 70000
111 array_init(&matrix);
112 php_imagickkernelvalues_to_zval(&matrix, kernel_info);
113 zend_hash_next_index_insert(debug_info, &matrix);
114 #else
115 MAKE_STD_ZVAL(matrix);
116 array_init(matrix);
117 php_imagickkernelvalues_to_zval(matrix, kernel_info);
118 zend_hash_next_index_insert(debug_info, &matrix, sizeof(zval *), NULL);
119 #endif
120 kernel_info = kernel_info->next;
121 }
122
123 return debug_info;
124 }
125
126
im_CalcKernelMetaData(KernelInfo * kernel)127 static void im_CalcKernelMetaData(KernelInfo *kernel) {
128 size_t i;
129
130 kernel->minimum = kernel->maximum = 0.0;
131 kernel->negative_range = kernel->positive_range = 0.0;
132
133 for (i=0; i < (kernel->width*kernel->height); i++) {
134 if (fabs(kernel->values[i]) < MagickEpsilon) {
135 kernel->values[i] = 0.0;
136 }
137 if (kernel->values[i] < 0) {
138 kernel->negative_range += kernel->values[i];
139 }
140 else {
141 kernel->positive_range += kernel->values[i];
142 }
143 if (kernel->values[i] < kernel->minimum) {
144 kernel->minimum = kernel->values[i];
145 }
146
147 if (kernel->values[i] > kernel->maximum) {
148 kernel->maximum = kernel->values[i];
149 }
150 }
151
152 return;
153 }
154
155
156 #if MagickLibVersion > 0x661
imagick_createKernel(KernelValueType * values,size_t width,size_t height,size_t origin_x,size_t origin_y)157 static KernelInfo *imagick_createKernel(KernelValueType *values, size_t width, size_t height, size_t origin_x, size_t origin_y)
158 {
159 KernelInfo *kernel_info;
160
161 #if MagickLibVersion >= 0x700
162 unsigned int i;
163 ExceptionInfo *_exception_info = (ExceptionInfo *) NULL;
164 //TODO - inspect exception info
165 kernel_info=AcquireKernelInfo(NULL, _exception_info);
166 #else
167 kernel_info=AcquireKernelInfo(NULL);
168 #endif
169 if (kernel_info == (KernelInfo *) NULL) {
170 return NULL;
171 }
172
173 kernel_info->width = width;
174 kernel_info->height = height;
175
176 kernel_info->x = origin_x;
177 kernel_info->y = origin_y;
178
179 //Need to free old values?
180 if (kernel_info->values != NULL) {
181 RelinquishAlignedMemory(kernel_info->values);
182 }
183
184 #if MagickLibVersion >= 0x700
185 kernel_info->values = (MagickRealType *)AcquireAlignedMemory(width*height, sizeof(MagickRealType));
186
187 for (i=0; i<width*height;i++) {
188 kernel_info->values[i] = (MagickRealType)values[i];
189 }
190
191 #else
192 kernel_info->values = values;
193 #endif
194
195 im_CalcKernelMetaData(kernel_info);
196
197 return kernel_info;
198 }
199 #endif
200
createKernelZval(zval * pzval,KernelInfo * kernel_info TSRMLS_DC)201 static void createKernelZval(zval *pzval, KernelInfo *kernel_info TSRMLS_DC) {
202 php_imagickkernel_object *intern_return;
203
204 object_init_ex(pzval, php_imagickkernel_sc_entry);
205 intern_return = Z_IMAGICKKERNEL_P(pzval);
206 intern_return->kernel_info = kernel_info;
207 }
208
209
210 /* {{{ proto ImagickKernel ImagickKernel::__construct()
211 The ImagickKernel constructor
212 */
PHP_METHOD(ImagickKernel,__construct)213 PHP_METHOD(ImagickKernel, __construct)
214 {
215 // This suppresses an 'unused parameter' warning.
216 (void)return_value;
217
218 if (zend_parse_parameters_none() == FAILURE) {
219 return;
220 }
221 // this method is private.
222 }
223 /* }}} */
224
225 #define MATRIX_ERROR_EMPTY "Cannot create kernel, matrix is empty."
226 #define MATRIX_ERROR_UNEVEN "Values must be matrix, with the same number of columns in each row."
227 #define MATRIX_ERROR_BAD_VALUE "Only numbers or false are valid values in a kernel matrix."
228 #define MATRIX_ORIGIN_REQUIRED "For kernels with even numbered rows or columns, the origin position must be specified."
229
230 /* {{{ proto ImagickKernel ImagickKernel::fromMatrix(array matrix, [array origin])
231 Create a kernel from an 2d matrix of values. Each value should either be a float
232 (if the element should be used) or 'false' if the element should be skipped. For
233 matrixes that are odd sizes in both dimensions the the origin pixel will default
234 to the centre of the kernel. For all other kernel sizes the origin pixel must be specified.
235 */
236 #if PHP_VERSION_ID >= 70000
PHP_METHOD(ImagickKernel,fromMatrix)237 PHP_METHOD(ImagickKernel, fromMatrix)
238
239 {
240 zval *kernel_array;
241 zval *origin_array;
242 HashTable *inner_array;
243 KernelInfo *kernel_info;
244 unsigned long num_rows, num_columns = 0;
245 unsigned int previous_num_columns = (unsigned int)-1;
246 unsigned int row, column;
247
248 zval *pzval_outer;
249 zval *pzval_inner;
250
251 int count = 0;
252 size_t origin_x, origin_y;
253 zval *tmp;
254
255 KernelValueType *values = NULL;
256 double notanumber = sqrt((double)-1.0); /* Special Value : Not A Number */
257
258 count = 0;
259 row = 0;
260 origin_array = NULL;
261
262 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|a", &kernel_array, &origin_array) == FAILURE) {
263 return;
264 }
265
266 num_rows = zend_hash_num_elements(Z_ARRVAL_P(kernel_array));
267
268 if (num_rows == 0) {
269 //error - array has zero elements.
270 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_EMPTY TSRMLS_CC);
271 return;
272 }
273
274
275 for (row=0 ; row<num_rows ; row++) {
276 pzval_outer = zend_hash_index_find(Z_ARRVAL_P(kernel_array), row);
277 if (pzval_outer == NULL) {
278 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
279 goto cleanup;
280 }
281 ZVAL_DEREF(pzval_outer);
282
283 column = 0;
284
285 if (Z_TYPE_P(pzval_outer) == IS_ARRAY ) {
286 inner_array = Z_ARRVAL_P(pzval_outer);
287 num_columns = zend_hash_num_elements(inner_array);
288
289 if (num_columns == 0) {
290 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_EMPTY TSRMLS_CC);
291 goto cleanup;
292 }
293
294 if (values == NULL) {
295 values = (KernelValueType *)AcquireAlignedMemory(num_columns, num_rows*sizeof(KernelValueType));
296 }
297
298 if (previous_num_columns != ((unsigned int)-1)) {
299 if (previous_num_columns != num_columns) {
300 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
301 goto cleanup;
302 }
303 }
304
305 previous_num_columns = num_columns;
306
307 for (column=0; column<num_columns ; column++) {
308 pzval_inner = zend_hash_index_find(inner_array, column);
309 if (pzval_inner == NULL) {
310 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
311 goto cleanup;
312 }
313
314 ZVAL_DEREF(pzval_inner);
315 if (Z_TYPE_P(pzval_inner) == IS_DOUBLE) {
316 //It's a float lets use it.
317 values[count] = Z_DVAL_P(pzval_inner);
318 }
319 else if (Z_TYPE_P(pzval_inner) == IS_LONG) {
320 //It's a long lets use it.
321 values[count] = (float)Z_LVAL_P(pzval_inner);
322 }
323 else if (Z_TYPE_P(pzval_inner) == IS_FALSE) {
324 //It's false, use nan
325 values[count] = notanumber;
326 }
327 else {
328 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_BAD_VALUE TSRMLS_CC);
329 goto cleanup;
330 }
331 count++;
332 }
333 }
334 else {
335 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
336 goto cleanup;
337 }
338 }
339
340 if (origin_array == NULL) {
341 if (((num_columns%2) == 0) || ((num_rows%2) == 0)) {
342 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
343 goto cleanup;
344 }
345 origin_x = (num_columns - 1) >> 1;
346 origin_y = (num_rows - 1) >> 1;
347 }
348 else {
349 HashTable *origin_array_ht;
350 origin_array_ht = Z_ARRVAL_P(origin_array);
351
352 // parse the origin_x
353 tmp = zend_hash_index_find(origin_array_ht, 0);
354 if (tmp != NULL) {
355 ZVAL_DEREF(tmp);
356 origin_x = Z_LVAL_P(tmp);
357 }
358 else {
359 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
360 goto cleanup;
361 }
362 // origin_x is unsigned, so checking for > num_columns, also
363 // checks for < 0
364 if (origin_x>=num_columns) {
365 zend_throw_exception_ex(
366 php_imagickkernel_exception_class_entry,
367 5 TSRMLS_CC,
368 "origin_x for matrix is outside bounds of columns: " ZEND_LONG_FMT,
369 origin_x
370 );
371 goto cleanup;
372 }
373
374 // parse the origin_y
375 tmp = zend_hash_index_find(origin_array_ht, 1);
376 if (tmp != NULL) {
377 ZVAL_DEREF(tmp);
378 origin_y = Z_LVAL_P(tmp);
379 }
380 else {
381 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
382 goto cleanup;
383 }
384 // origin_y is unsigned, so checking for > num_rows, also
385 // checks for < 0
386 if (origin_y>=num_rows) {
387 zend_throw_exception_ex(
388 php_imagickkernel_exception_class_entry,
389 5 TSRMLS_CC,
390 "origin_y for matrix is outside bounds of rows: " ZEND_LONG_FMT,
391 origin_x
392 );
393 goto cleanup;
394 }
395 }
396
397 kernel_info = imagick_createKernel(values, num_columns, num_rows, origin_x, origin_y);
398 createKernelZval(return_value, kernel_info TSRMLS_CC);
399
400 return;
401
402 cleanup:
403 if (values != NULL) {
404 RelinquishAlignedMemory(values);
405 }
406 }
407
408 #else // PHP 5
409
410
PHP_METHOD(ImagickKernel,fromMatrix)411 PHP_METHOD(ImagickKernel, fromMatrix)
412 {
413 zval *kernel_array;
414 zval *origin_array;
415 HashTable *inner_array;
416 KernelInfo *kernel_info;
417 unsigned long num_rows, num_columns = 0;
418 unsigned int previous_num_columns = (unsigned int)-1;
419 unsigned int row, column;
420
421 HashTable *origin_array_ht;
422 zval **ppzval_outer;
423 zval **ppzval_inner;
424
425 int count = 0;
426 size_t origin_x, origin_y;
427 zval **tmp;
428
429 KernelValueType *values = NULL;
430 double notanumber = sqrt((double)-1.0); /* Special Value : Not A Number */
431
432 previous_num_columns = -1;
433 count = 0;
434 row = 0;
435 origin_array = NULL;
436
437 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|a", &kernel_array, &origin_array) == FAILURE) {
438 return;
439 }
440
441 num_rows = zend_hash_num_elements(Z_ARRVAL_P(kernel_array));
442
443 if (num_rows == 0) {
444 //error - array has zero elements.
445 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_EMPTY TSRMLS_CC);
446 return;
447 }
448
449 for (row=0 ; row<num_rows ; row++) {
450 if (zend_hash_index_find(Z_ARRVAL_P(kernel_array), row, (void **) &ppzval_outer) != SUCCESS) {
451 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
452 goto cleanup;
453 }
454
455 column = 0;
456
457 if (Z_TYPE_PP(ppzval_outer) == IS_ARRAY ) {
458 //parse this row
459 inner_array = Z_ARRVAL_PP(ppzval_outer);
460 num_columns = zend_hash_num_elements(inner_array);
461
462 if (num_columns == 0) {
463 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_EMPTY TSRMLS_CC);
464 goto cleanup;
465 }
466
467 if (values == NULL) {
468 values = (KernelValueType *)AcquireAlignedMemory(num_columns, num_rows*sizeof(KernelValueType));
469 }
470
471 if (previous_num_columns != ((unsigned int)-1)) {
472 if (previous_num_columns != num_columns) {
473 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
474 goto cleanup;
475 }
476 }
477
478 previous_num_columns = num_columns;
479
480 for (column=0; column<num_columns ; column++) {
481 if (zend_hash_index_find(inner_array, column, (void **) &ppzval_inner) != SUCCESS) {
482 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
483 goto cleanup;
484 }
485
486 if (Z_TYPE_PP(ppzval_inner) == IS_DOUBLE) {
487 //It's a float lets use it.
488 values[count] = Z_DVAL_PP(ppzval_inner);
489 }
490 else if (Z_TYPE_PP(ppzval_inner) == IS_LONG) {
491 //It's a long lets use it.
492 values[count] = (float)Z_LVAL_PP(ppzval_inner);
493 }
494 else if (Z_TYPE_PP(ppzval_inner) == IS_BOOL && Z_BVAL_PP(ppzval_inner) == 0) {
495 //It's false, use nan
496 values[count] = notanumber;
497 }
498 else {
499 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_BAD_VALUE TSRMLS_CC);
500 goto cleanup;
501 }
502 count++;
503 }
504 }
505 else {
506 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ERROR_UNEVEN TSRMLS_CC);
507 goto cleanup;
508 }
509 }
510
511 if (origin_array == NULL) {
512 if (((num_columns%2) == 0) || ((num_rows%2) == 0)) {
513 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
514 goto cleanup;
515 }
516 origin_x = (num_columns - 1) >> 1;
517 origin_y = (num_rows - 1) >> 1;
518 }
519 else {
520 origin_array_ht = Z_ARRVAL_P(origin_array);
521
522 // parse and check the origin_x
523 if (zend_hash_index_find(origin_array_ht, 0, (void**)&tmp) == SUCCESS) {
524 origin_x = Z_LVAL_PP(tmp);
525 }
526 else {
527 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
528 goto cleanup;
529 }
530
531 // origin_x is unsigned, so checking for > num_columns, also
532 // checks for < 0
533 if (origin_x>=num_columns) {
534 zend_throw_exception_ex(
535 php_imagickkernel_exception_class_entry,
536 5 TSRMLS_CC,
537 "origin_x for matrix is outside bounds of columns: %d",
538 origin_x
539 );
540 goto cleanup;
541 }
542
543 // parse and check the origin_y
544 if (zend_hash_index_find(origin_array_ht, 1, (void**)&tmp) == SUCCESS) {
545 origin_y = Z_LVAL_PP(tmp);
546 }
547 else {
548 php_imagick_throw_exception(IMAGICKKERNEL_CLASS, MATRIX_ORIGIN_REQUIRED TSRMLS_CC);
549 goto cleanup;
550 }
551
552 // origin_y is unsigned, so checking for > num_rows, also
553 // checks for < 0
554 if (origin_y>=num_rows) {
555 zend_throw_exception_ex(
556 php_imagickkernel_exception_class_entry,
557 5 TSRMLS_CC,
558 "origin_y for matrix is outside bounds of rows: %d",
559 origin_y
560 );
561 goto cleanup;
562 }
563 }
564
565 kernel_info = imagick_createKernel(values, num_columns, num_rows, origin_x, origin_y);
566 createKernelZval(return_value, kernel_info TSRMLS_CC);
567
568 return;
569
570 cleanup:
571 if (values != NULL) {
572 RelinquishAlignedMemory(values);
573 }
574 }
575 #endif //end of zend_engine_3
576 /* }}} */
577
imagick_fiddle_with_geometry_info(ssize_t type,GeometryFlags flags,GeometryInfo * geometry_info)578 static void imagick_fiddle_with_geometry_info(ssize_t type, GeometryFlags flags, GeometryInfo *geometry_info) {
579
580 /* special handling of missing values in input string */
581 switch( type ) {
582 /* Shape Kernel Defaults */
583 case UnityKernel: {
584 if ((flags & WidthValue) == 0)
585 geometry_info->rho = 1.0; /* Default scale = 1.0, zero is valid */
586 break;
587 }
588 case SquareKernel:
589 case DiamondKernel:
590 case OctagonKernel:
591 case DiskKernel:
592 case PlusKernel:
593 case CrossKernel: {
594 if ( (flags & HeightValue) == 0 ) {
595 geometry_info->sigma = 1.0; /* Default scale = 1.0, zero is valid */
596 }
597 break;
598 }
599 case RingKernel: {
600 if ((flags & XValue) == 0) {
601 geometry_info->xi = 1.0; /* Default scale = 1.0, zero is valid */
602 }
603 break;
604 }
605 case RectangleKernel: { /* Rectangle - set size defaults */
606 if ((flags & WidthValue) == 0) { /* if no width then */
607 geometry_info->rho = geometry_info->sigma; /* then width = height */
608 }
609 if (geometry_info->rho < 1.0) { /* if width too small */
610 geometry_info->rho = 3; /* then width = 3 */
611 }
612 if (geometry_info->sigma < 1.0) { /* if height too small */
613 geometry_info->sigma = geometry_info->rho; /* then height = width */
614 }
615 if ((flags & XValue) == 0) { /* center offset if not defined */
616 geometry_info->xi = (double)(((ssize_t)geometry_info->rho-1)/2);
617 }
618 if ((flags & YValue) == 0) {
619 geometry_info->psi = (double)(((ssize_t)geometry_info->sigma-1)/2);
620 }
621 break;
622 }
623 /* Distance Kernel Defaults */
624 case ChebyshevKernel:
625 case ManhattanKernel:
626 case OctagonalKernel:
627 case EuclideanKernel: {
628 if ((flags & HeightValue) == 0) { /* no distance scale */
629 geometry_info->sigma = 100.0; /* default distance scaling */
630 }
631 else if ((flags & AspectValue ) != 0) { /* '!' flag */
632 geometry_info->sigma = QuantumRange/(geometry_info->sigma+1); /* maximum pixel distance */
633 }
634 else if ((flags & PercentValue ) != 0) { /* '%' flag */
635 geometry_info->sigma *= QuantumRange/100.0; /* percentage of color range */
636 }
637 break;
638 }
639 default: {
640 break;
641 }
642 }
643 }
644
645 /* {{{ proto ImagickKernel ImagickKernel::fromBuiltin(type, string)
646 Create a kernel from a builtin in kernel. See http://www.imagemagick.org/Usage/morphology/#kernel for examples. Currently the 'rotation' symbols are not supported. Example:
647 $diamondKernel = ImagickKernel::fromBuiltIn(\Imagick::KERNEL_DIAMOND, "2");
648 */
PHP_METHOD(ImagickKernel,fromBuiltin)649 PHP_METHOD(ImagickKernel, fromBuiltin)
650 {
651 im_long kernel_type;
652 GeometryInfo geometry_info = {
653 0, //rho,
654 0, //sigma,
655 0, //xi,
656 0, //psi,
657 0, //chi;
658 };
659 KernelInfo *kernel_info;
660 char *string;
661 IM_LEN_TYPE string_len;
662 GeometryFlags flags;
663 #if MagickLibVersion >= 0x700
664 ExceptionInfo *_exception_info = NULL;
665 #endif
666
667 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &kernel_type, &string, &string_len) == FAILURE) {
668 return;
669 }
670
671 flags = ParseGeometry(string, &geometry_info);
672 imagick_fiddle_with_geometry_info(kernel_type, flags, &geometry_info);
673
674 #if MagickLibVersion >= 0x700
675 //TODO - inspect exception info
676 kernel_info = AcquireKernelBuiltIn(kernel_type, &geometry_info, _exception_info);
677 #else
678 kernel_info = AcquireKernelBuiltIn(kernel_type, &geometry_info);
679 #endif
680 createKernelZval(return_value, kernel_info TSRMLS_CC);
681
682 return;
683 }
684
685 /* }}} */
686
687
688 /* {{{ proto void ImagickKernel::addKernel(ImagickKernel kernel)
689 Attach another kernel to this kernel to allow them to both be applied in a single morphology or filter function. Returns the new combined kernel.
690 */
PHP_METHOD(ImagickKernel,addKernel)691 PHP_METHOD(ImagickKernel, addKernel)
692 {
693 zval *objvar;
694 KernelInfo *kernel_info_add_clone;
695
696 KernelInfo *kernel_info;
697 KernelInfo *kernel_info_target;
698
699 php_imagickkernel_object *kernel;
700 php_imagickkernel_object *internp;
701
702 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &objvar, php_imagickkernel_sc_entry) == FAILURE) {
703 return;
704 }
705
706 kernel = Z_IMAGICKKERNEL_P(objvar);
707 internp = Z_IMAGICKKERNEL_P(getThis());
708
709 if (kernel->kernel_info == NULL) {
710 zend_throw_exception(php_imagickkernel_exception_class_entry, "ImagickKernel is empty, cannot be used", (long)0 TSRMLS_CC);
711 RETURN_NULL();
712 }
713
714 kernel_info = internp->kernel_info;
715 do {
716 kernel_info_target = kernel_info;
717 kernel_info = kernel_info->next;
718 } while (kernel_info != NULL);
719
720 kernel_info_add_clone = CloneKernelInfo(kernel->kernel_info);
721 kernel_info_target->next = kernel_info_add_clone;
722
723 return;
724 }
725 /* }}} */
726
727
728 /* {{{ proto ImagickKernel[] ImagickKernel::separate(void)
729 Separates a linked set of kernels and returns an array of ImagickKernels.
730 */
PHP_METHOD(ImagickKernel,separate)731 PHP_METHOD(ImagickKernel, separate)
732 {
733 php_imagickkernel_object *internp;
734 KernelInfo *kernel_info;
735 KernelInfo *kernel_info_copy;
736 int number_values;
737 KernelValueType * values_copy;
738
739 #if PHP_VERSION_ID >= 70000
740 zval separate_object;
741 #else
742 zval *separate_object;
743 #endif
744
745 if (zend_parse_parameters_none() == FAILURE) {
746 return;
747 }
748
749 internp = Z_IMAGICKKERNEL_P(getThis());
750 IMAGICK_KERNEL_NOT_NULL_EMPTY(internp);
751 kernel_info = internp->kernel_info;
752
753 array_init(return_value);
754
755 while (kernel_info != NULL) {
756 number_values = kernel_info->width * kernel_info->height;
757 values_copy = (KernelValueType *)AcquireAlignedMemory(kernel_info->width, kernel_info->height*sizeof(KernelValueType));
758 memcpy(values_copy, kernel_info->values, number_values * sizeof(KernelValueType));
759
760 kernel_info_copy = imagick_createKernel(
761 values_copy,
762 kernel_info->width,
763 kernel_info->height,
764 kernel_info->x,
765 kernel_info->y
766 );
767
768 #if PHP_VERSION_ID >= 70000
769 createKernelZval(&separate_object, kernel_info_copy TSRMLS_CC);
770 add_next_index_zval(return_value, &separate_object);
771 #else
772 MAKE_STD_ZVAL(separate_object);
773 createKernelZval(separate_object, kernel_info_copy TSRMLS_CC);
774 add_next_index_zval(return_value, separate_object);
775 #endif
776 kernel_info = kernel_info->next;
777 }
778
779 return;
780 }
781 /* }}} */
782
783
784 /* {{{ proto [] ImagickKernel::getMatrix(void)
785 Get the 2d matrix of values used in this kernel. The elements are either
786 float for elements that are used or 'false' if the element should be skipped.
787 */
PHP_METHOD(ImagickKernel,getMatrix)788 PHP_METHOD(ImagickKernel, getMatrix)
789 {
790 php_imagickkernel_object *internp;
791
792 if (zend_parse_parameters_none() == FAILURE) {
793 return;
794 }
795
796 internp = Z_IMAGICKKERNEL_P(getThis());
797 IMAGICK_KERNEL_NOT_NULL_EMPTY(internp);
798
799 array_init(return_value);
800 php_imagickkernelvalues_to_zval(return_value, internp->kernel_info);
801
802 return;
803 }
804 /* }}} */
805
806
807
808
809
810 /* {{{ proto [] ImagickKernel::scale(float scaling_factor[, int NORMALIZE_KERNEL_FLAG])
811 ScaleKernelInfo() scales the given kernel list by the given amount, with or without
812 normalization of the sum of the kernel values (as per given flags).
813
814 The exact behaviour of this function depends on the normalization type being used
815 please see http://www.imagemagick.org/api/morphology.php#ScaleKernelInfo for details.
816
817 Flag should be one of NORMALIZE_KERNEL_VALUE, NORMALIZE_KERNEL_CORRELATE,
818 NORMALIZE_KERNEL_PERCENT or not set.
819 */
PHP_METHOD(ImagickKernel,scale)820 PHP_METHOD(ImagickKernel, scale)
821 {
822 php_imagickkernel_object *internp;
823 double scale;
824 im_long normalize_flag = 0;
825
826 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|l", &scale, &normalize_flag) == FAILURE) {
827 return;
828 }
829
830 internp = Z_IMAGICKKERNEL_P(getThis());
831 IMAGICK_KERNEL_NOT_NULL_EMPTY(internp);
832 ScaleKernelInfo(internp->kernel_info, scale, normalize_flag);
833
834 return;
835 }
836 /* }}} */
837
838
839
840
841 /* {{{ proto [] ImagickKernel::addUnityKernel(float scale)
842 Adds a given amount of the 'Unity' Convolution Kernel to the given pre-scaled
843 and normalized Kernel. This in effect adds that amount of the original image
844 into the resulting convolution kernel. The resulting effect is to convert the
845 defined kernels into blended soft-blurs, unsharp kernels or into sharpening kernels.
846 */
PHP_METHOD(ImagickKernel,addUnityKernel)847 PHP_METHOD(ImagickKernel, addUnityKernel)
848 {
849 php_imagickkernel_object *internp;
850 double scale;
851
852 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &scale) == FAILURE) {
853 return;
854 }
855
856 internp = Z_IMAGICKKERNEL_P(getThis());
857 IMAGICK_KERNEL_NOT_NULL_EMPTY(internp);
858 UnityAddKernelInfo(internp->kernel_info, scale);
859
860 return;
861 }
862 /* }}} */
863
864 #endif
865