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