1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4 
5 #include "php.h"
6 #include "php_ini.h"
7 #include "ext/standard/info.h"
8 #include <puzzle.h>
9 #include "php_libpuzzle.h"
10 
ZEND_DECLARE_MODULE_GLOBALS(libpuzzle)11 ZEND_DECLARE_MODULE_GLOBALS(libpuzzle)
12 
13 /* True global resources - no need for thread safety here */
14 static int le_libpuzzle;
15 
16 /* {{{ libpuzzle_functions[]
17  */
18 zend_function_entry libpuzzle_functions[] = {
19         PHP_FE(puzzle_set_max_width, NULL)
20         PHP_FE(puzzle_set_max_height, NULL)
21         PHP_FE(puzzle_set_lambdas, NULL)
22         PHP_FE(puzzle_set_noise_cutoff, NULL)
23         PHP_FE(puzzle_set_p_ratio, NULL)
24         PHP_FE(puzzle_set_contrast_barrier_for_cropping, NULL)
25         PHP_FE(puzzle_set_max_cropping_ratio, NULL)
26         PHP_FE(puzzle_set_autocrop, NULL)
27 
28         PHP_FE(puzzle_fill_cvec_from_file, NULL)
29         PHP_FE(puzzle_compress_cvec, NULL)
30         PHP_FE(puzzle_uncompress_cvec, NULL)
31         PHP_FE(puzzle_vector_normalized_distance, NULL)
32 
33         {NULL, NULL, NULL}      /* Must be the last line in libpuzzle_functions[] */
34 };
35 /* }}} */
36 
37 /* {{{ libpuzzle_module_entry
38  */
39 zend_module_entry libpuzzle_module_entry = {
40 #if ZEND_MODULE_API_NO >= 20010901
41         STANDARD_MODULE_HEADER,
42 #endif
43         "libpuzzle",
44         libpuzzle_functions,
45         PHP_MINIT(libpuzzle),
46         PHP_MSHUTDOWN(libpuzzle),
47         PHP_RINIT(libpuzzle),           /* Replace with NULL if there's nothing to do at request start */
48         PHP_RSHUTDOWN(libpuzzle),       /* Replace with NULL if there's nothing to do at request end */
49         PHP_MINFO(libpuzzle),
50 #if ZEND_MODULE_API_NO >= 20010901
51         "0.10", /* Replace with version number for your extension */
52 #endif
53         STANDARD_MODULE_PROPERTIES
54 };
55 /* }}} */
56 
57 #ifdef COMPILE_DL_LIBPUZZLE
58 ZEND_GET_MODULE(libpuzzle)
59 #endif
60 
61 
62 /* {{{ PHP_MINIT_FUNCTION
63  */
PHP_MINIT_FUNCTION(libpuzzle)64 PHP_MINIT_FUNCTION(libpuzzle)
65 {
66     REGISTER_DOUBLE_CONSTANT("PUZZLE_CVEC_SIMILARITY_THRESHOLD",
67                              PUZZLE_CVEC_SIMILARITY_THRESHOLD,
68                              CONST_CS | CONST_PERSISTENT);
69     REGISTER_DOUBLE_CONSTANT("PUZZLE_CVEC_SIMILARITY_HIGH_THRESHOLD",
70                              PUZZLE_CVEC_SIMILARITY_HIGH_THRESHOLD,
71                              CONST_CS | CONST_PERSISTENT);
72     REGISTER_DOUBLE_CONSTANT("PUZZLE_CVEC_SIMILARITY_LOW_THRESHOLD",
73                              PUZZLE_CVEC_SIMILARITY_LOW_THRESHOLD,
74                              CONST_CS | CONST_PERSISTENT);
75     REGISTER_DOUBLE_CONSTANT("PUZZLE_CVEC_SIMILARITY_LOWER_THRESHOLD",
76                              PUZZLE_CVEC_SIMILARITY_LOWER_THRESHOLD,
77                              CONST_CS | CONST_PERSISTENT);
78     return SUCCESS;
79 }
80 /* }}} */
81 
82 /* {{{ PHP_MSHUTDOWN_FUNCTION
83  */
PHP_MSHUTDOWN_FUNCTION(libpuzzle)84 PHP_MSHUTDOWN_FUNCTION(libpuzzle)
85 {
86         return SUCCESS;
87 }
88 /* }}} */
89 
90 /* Remove if there's nothing to do at request start */
91 /* {{{ PHP_RINIT_FUNCTION
92  */
PHP_RINIT_FUNCTION(libpuzzle)93 PHP_RINIT_FUNCTION(libpuzzle)
94 {
95     puzzle_init_context(&LIBPUZZLE_G(global_context));
96     return SUCCESS;
97 }
98 /* }}} */
99 
100 /* Remove if there's nothing to do at request end */
101 /* {{{ PHP_RSHUTDOWN_FUNCTION
102  */
PHP_RSHUTDOWN_FUNCTION(libpuzzle)103 PHP_RSHUTDOWN_FUNCTION(libpuzzle)
104 {
105     puzzle_free_context(&LIBPUZZLE_G(global_context));
106     return SUCCESS;
107 }
108 /* }}} */
109 
110 /* {{{ PHP_MINFO_FUNCTION
111  */
PHP_MINFO_FUNCTION(libpuzzle)112 PHP_MINFO_FUNCTION(libpuzzle)
113 {
114         php_info_print_table_start();
115         php_info_print_table_header(2, "libpuzzle support", "enabled");
116         php_info_print_table_end();
117 }
118 /* }}} */
119 
120 /* {{{ proto string puzzle_fill_cvec_from_file(string filename)
121  * Creates a signature out of an image file */
PHP_FUNCTION(puzzle_fill_cvec_from_file)122 PHP_FUNCTION(puzzle_fill_cvec_from_file)
123 {
124     char *arg = NULL;
125     int arg_len;
126     PuzzleContext *context;
127     PuzzleCvec cvec;
128 
129     context = &LIBPUZZLE_G(global_context);
130     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
131                               "s", &arg, &arg_len) == FAILURE ||
132         arg_len <= 0) {
133         RETURN_FALSE;
134     }
135     puzzle_init_cvec(context, &cvec);
136     if (puzzle_fill_cvec_from_file(context, &cvec, arg) != 0) {
137         puzzle_free_cvec(context, &cvec);
138         RETURN_FALSE;
139     }
140     RETVAL_STRINGL(cvec.vec, cvec.sizeof_vec, 1);
141     puzzle_free_cvec(context, &cvec);
142 }
143 /* }}} */
144 
145 /* {{{ proto string puzzle_compress_cvec(string cvec)
146  * Compress a signature to save storage space */
PHP_FUNCTION(puzzle_compress_cvec)147 PHP_FUNCTION(puzzle_compress_cvec)
148 {
149     char *arg = NULL;
150     int arg_len;
151     PuzzleContext *context;
152     PuzzleCompressedCvec compressed_cvec;
153     PuzzleCvec cvec;
154 
155     context = &LIBPUZZLE_G(global_context);
156     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
157                               "s", &arg, &arg_len) == FAILURE ||
158         arg_len <= 0) {
159         RETURN_FALSE;
160     }
161     puzzle_init_compressed_cvec(context, &compressed_cvec);
162     puzzle_init_cvec(context, &cvec);
163     cvec.vec = arg;
164     cvec.sizeof_vec = (size_t) arg_len;
165     if (puzzle_compress_cvec(context, &compressed_cvec, &cvec) != 0) {
166         puzzle_free_compressed_cvec(context, &compressed_cvec);
167         cvec.vec = NULL;
168         puzzle_free_cvec(context, &cvec);
169         RETURN_FALSE;
170     }
171     RETVAL_STRINGL(compressed_cvec.vec,
172                    compressed_cvec.sizeof_compressed_vec, 1);
173     puzzle_free_compressed_cvec(context, &compressed_cvec);
174     cvec.vec = NULL;
175     puzzle_free_cvec(context, &cvec);
176 }
177 /* }}} */
178 
179 /* {{{ proto string puzzle_uncompress_cvec(string compressed_cvec)
180  * Uncompress a compressed signature so that it can be used for computations */
PHP_FUNCTION(puzzle_uncompress_cvec)181 PHP_FUNCTION(puzzle_uncompress_cvec)
182 {
183     char *arg = NULL;
184     int arg_len;
185     PuzzleContext *context;
186     PuzzleCompressedCvec compressed_cvec;
187     PuzzleCvec cvec;
188 
189     context = &LIBPUZZLE_G(global_context);
190     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
191                               "s", &arg, &arg_len) == FAILURE ||
192         arg_len <= 0) {
193         RETURN_FALSE;
194     }
195     puzzle_init_compressed_cvec(context, &compressed_cvec);
196     puzzle_init_cvec(context, &cvec);
197     compressed_cvec.vec = arg;
198     compressed_cvec.sizeof_compressed_vec = (size_t) arg_len;
199     if (puzzle_uncompress_cvec(context, &compressed_cvec, &cvec) != 0) {
200         puzzle_free_cvec(context, &cvec);
201         compressed_cvec.vec = NULL;
202         puzzle_free_compressed_cvec(context, &compressed_cvec);
203         RETURN_FALSE;
204     }
205     RETVAL_STRINGL(cvec.vec, cvec.sizeof_vec, 1);
206     puzzle_free_cvec(context, &cvec);
207     compressed_cvec.vec = NULL;
208     puzzle_free_compressed_cvec(context, &compressed_cvec);
209 }
210 /* }}} */
211 
212 /* {{{ proto double puzzle_vector_normalized_distance(string cvec1, string cvec2 [, bool fix_for_texts])
213  * Computes the distance between two signatures. Result is between 0.0 and 1.0 */
PHP_FUNCTION(puzzle_vector_normalized_distance)214 PHP_FUNCTION(puzzle_vector_normalized_distance)
215 {
216     char *vec1 = NULL, *vec2 = NULL;
217     int vec1_len, vec2_len;
218     PuzzleContext *context;
219     PuzzleCvec cvec1, cvec2;
220     double d;
221     zend_bool fix_for_texts;
222 
223     context = &LIBPUZZLE_G(global_context);
224     if (zend_parse_parameters
225         (ZEND_NUM_ARGS() TSRMLS_CC, "ss|b",
226          &vec1, &vec1_len, &vec2, &vec2_len, &fix_for_texts) == FAILURE ||
227         vec1_len <= 0 || vec2_len <= 0) {
228         RETURN_FALSE;
229     }
230     if (ZEND_NUM_ARGS() TSRMLS_CC < 3) {
231         fix_for_texts = (zend_bool) 1;
232     }
233     puzzle_init_cvec(context, &cvec1);
234     puzzle_init_cvec(context, &cvec2);
235     cvec1.vec = vec1;
236     cvec1.sizeof_vec = (size_t) vec1_len;
237     cvec2.vec = vec2;
238     cvec2.sizeof_vec = (size_t) vec2_len;
239     d = puzzle_vector_normalized_distance(context, &cvec1, &cvec2,
240                                           (int) fix_for_texts);
241     cvec1.vec = cvec2.vec = NULL;
242     puzzle_free_cvec(context, &cvec1);
243     puzzle_free_cvec(context, &cvec2);
244     RETVAL_DOUBLE(d);
245 }
246 /* }}} */
247 
248 /* {{{ proto bool puzzle_set_max_width(int width)
249  * Set the maximum picture width */
PHP_FUNCTION(puzzle_set_max_width)250 PHP_FUNCTION(puzzle_set_max_width)
251 {
252     PuzzleContext *context;
253     long width;
254 
255     context = &LIBPUZZLE_G(global_context);
256     if (zend_parse_parameters
257         (ZEND_NUM_ARGS() TSRMLS_CC, "l", &width) == FAILURE ||
258         width <= 0L || width > INT_MAX) {
259         RETURN_FALSE;
260     }
261     if (puzzle_set_max_width(context, (unsigned int) width) != 0) {
262         RETURN_FALSE;
263     }
264     RETVAL_TRUE;
265 }
266 /* }}} */
267 
268 /* {{{ proto bool puzzle_set_max_height(int height)
269  * Set the maximum picture height */
PHP_FUNCTION(puzzle_set_max_height)270 PHP_FUNCTION(puzzle_set_max_height)
271 {
272     PuzzleContext *context;
273     long height;
274 
275     context = &LIBPUZZLE_G(global_context);
276     if (zend_parse_parameters
277         (ZEND_NUM_ARGS() TSRMLS_CC, "l", &height) == FAILURE ||
278         height <= 0L || height > INT_MAX) {
279         RETURN_FALSE;
280     }
281     if (puzzle_set_max_height(context, (unsigned int) height) != 0) {
282         RETURN_FALSE;
283     }
284     RETVAL_TRUE;
285 }
286 /* }}} */
287 
288 /* {{{ proto bool puzzle_set_lambdas(int lambdas)
289  * Set the size of the computation grid */
PHP_FUNCTION(puzzle_set_lambdas)290 PHP_FUNCTION(puzzle_set_lambdas)
291 {
292     PuzzleContext *context;
293     long lambdas;
294 
295     context = &LIBPUZZLE_G(global_context);
296     if (zend_parse_parameters
297         (ZEND_NUM_ARGS() TSRMLS_CC, "l", &lambdas) == FAILURE ||
298         lambdas <= 0L || lambdas > INT_MAX) {
299         RETURN_FALSE;
300     }
301     if (puzzle_set_lambdas(context, (unsigned int) lambdas) != 0) {
302         RETURN_FALSE;
303     }
304     RETVAL_TRUE;
305 }
306 /* }}} */
307 
308 /* {{{ proto bool puzzle_set_noise_cutoff(double cutoff)
309  * Set the noise cutoff level */
PHP_FUNCTION(puzzle_set_noise_cutoff)310 PHP_FUNCTION(puzzle_set_noise_cutoff)
311 {
312     PuzzleContext *context;
313     double cutoff;
314 
315     context = &LIBPUZZLE_G(global_context);
316     if (zend_parse_parameters
317         (ZEND_NUM_ARGS() TSRMLS_CC, "d", &cutoff) == FAILURE) {
318         RETURN_FALSE;
319     }
320     if (puzzle_set_noise_cutoff(context, cutoff) != 0) {
321         RETURN_FALSE;
322     }
323     RETVAL_TRUE;
324 }
325 /* }}} */
326 
327 /* {{{ proto bool puzzle_set_p_ratio(double ratio)
328  * Set the p_ratio */
PHP_FUNCTION(puzzle_set_p_ratio)329 PHP_FUNCTION(puzzle_set_p_ratio)
330 {
331     PuzzleContext *context;
332     double p_ratio;
333 
334     context = &LIBPUZZLE_G(global_context);
335     if (zend_parse_parameters
336         (ZEND_NUM_ARGS() TSRMLS_CC, "d", &p_ratio) == FAILURE) {
337         RETURN_FALSE;
338     }
339     if (puzzle_set_p_ratio(context, p_ratio) != 0) {
340         RETURN_FALSE;
341     }
342     RETVAL_TRUE;
343 }
344 /* }}} */
345 
346 /* {{{ proto bool puzzle_set_contrast_barrier_for_cropping(double barrier)
347  * Set the tolerance level for cropping */
PHP_FUNCTION(puzzle_set_contrast_barrier_for_cropping)348 PHP_FUNCTION(puzzle_set_contrast_barrier_for_cropping)
349 {
350     PuzzleContext *context;
351     double barrier;
352 
353     context = &LIBPUZZLE_G(global_context);
354     if (zend_parse_parameters
355         (ZEND_NUM_ARGS() TSRMLS_CC, "d", &barrier) == FAILURE) {
356         RETURN_FALSE;
357     }
358     if (puzzle_set_contrast_barrier_for_cropping(context, barrier) != 0) {
359         RETURN_FALSE;
360     }
361     RETVAL_TRUE;
362 }
363 /* }}} */
364 
365 /* {{{ proto bool puzzle_set_max_cropping_ratio(double ratio)
366  * Set the maximum ratio between the cropped area and the whole picture */
PHP_FUNCTION(puzzle_set_max_cropping_ratio)367 PHP_FUNCTION(puzzle_set_max_cropping_ratio)
368 {
369     PuzzleContext *context;
370     double ratio;
371 
372     context = &LIBPUZZLE_G(global_context);
373     if (zend_parse_parameters
374         (ZEND_NUM_ARGS() TSRMLS_CC, "d", &ratio) == FAILURE) {
375         RETURN_FALSE;
376     }
377     if (puzzle_set_max_cropping_ratio(context, ratio) != 0) {
378         RETURN_FALSE;
379     }
380     RETVAL_TRUE;
381 }
382 /* }}} */
383 
384 /* {{{ proto bool puzzle_set_autocrop(bool autocrop)
385  * TRUE to enable autocropping, FALSE to disable */
PHP_FUNCTION(puzzle_set_autocrop)386 PHP_FUNCTION(puzzle_set_autocrop)
387 {
388     PuzzleContext *context;
389     zend_bool autocrop;
390 
391     context = &LIBPUZZLE_G(global_context);
392     if (zend_parse_parameters
393         (ZEND_NUM_ARGS() TSRMLS_CC, "b", &autocrop) == FAILURE) {
394         RETURN_FALSE;
395     }
396     if (puzzle_set_autocrop(context, (int) autocrop) != 0) {
397         RETURN_FALSE;
398     }
399     RETVAL_TRUE;
400 }
401 /* }}} */
402 
403 /*
404  * Local variables:
405  * tab-width: 4
406  * c-basic-offset: 4
407  * End:
408  * vim600: noet sw=4 ts=4 fdm=marker
409  * vim<600: noet sw=4 ts=4
410  */
411