]> git.imager.perl.org - imager.git/blame - Imager.xs
don't match against horizontal lines
[imager.git] / Imager.xs
CommitLineData
b13a3ddb 1#define PERL_NO_GET_CONTEXT
02d1d628
AMH
2#ifdef __cplusplus
3extern "C" {
4#endif
5#include "EXTERN.h"
6#include "perl.h"
7#include "XSUB.h"
7a6cd05b
TC
8#define NEED_newRV_noinc
9#define NEED_sv_2pv_nolen
f35d1231 10#define NEED_sv_2pvbyte
02d1d628
AMH
11#include "ppport.h"
12#ifdef __cplusplus
92bda632 13}
02d1d628
AMH
14#endif
15
a8652edf
TC
16#define i_int_hlines_testing() 1
17
92bda632 18#include "imager.h"
02d1d628
AMH
19#include "feat.h"
20#include "dynaload.h"
21#include "regmach.h"
92bda632 22#include "imextdef.h"
ec6d8908 23#include "imextpltypes.h"
52d990d6 24#include "imperlio.h"
4498c8bd 25#include <float.h>
a8652edf 26
92bda632
TC
27#if i_int_hlines_testing()
28#include "imageri.h"
02d1d628
AMH
29#endif
30
92bda632 31#include "imperl.h"
faa9b3e7 32
31a13473
TC
33/*
34
35Context object management
36
37*/
38
39typedef im_context_t Imager__Context;
40
41#define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY")
42
43#ifdef PERL_IMPLICIT_CONTEXT
44
45#define MY_CXT_KEY "Imager::_context" XS_VERSION
46
47typedef struct {
48 im_context_t ctx;
49} my_cxt_t;
50
51START_MY_CXT
52
53im_context_t fallback_context;
54
55static void
56start_context(pTHX) {
57 dMY_CXT;
58 MY_CXT.ctx = im_context_new();
59 sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
60
61 /* Ideally we'd free this reference, but the error message memory
62 was never released on exit, so the associated memory here is reasonable
63 to keep.
64 With logging enabled we always need at least one context, since
65 objects may be released fairly late and attempt to get the log file.
66 */
67 im_context_refinc(MY_CXT.ctx, "start_context");
68 fallback_context = MY_CXT.ctx;
69}
70
71static im_context_t
72perl_get_context(void) {
73 dTHX;
74 dMY_CXT;
75
76 return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
77}
78
79#else
80
81static im_context_t perl_context;
82
83static void
84start_context(pTHX) {
85 perl_context = im_context_new();
86 im_context_refinc(perl_context, "start_context");
87}
cf8c77ae
TC
88
89static im_context_t
90perl_get_context(void) {
31a13473 91 return perl_context;
cf8c77ae
TC
92}
93
31a13473
TC
94#endif
95
6a9807e8
TC
96/* used to represent channel lists parameters */
97typedef struct i_channel_list_tag {
98 int *channels;
99 int count;
100} i_channel_list;
101
48b9a7bf
TC
102typedef struct {
103 size_t count;
104 const i_sample_t *samples;
105} i_sample_list;
106
107typedef struct {
108 size_t count;
109 const i_fsample_t *samples;
110} i_fsample_list;
111
ebe9b189
TC
112/*
113
114Allocate memory that will be discarded when mortals are discarded.
115
116*/
117
118static void *
119malloc_temp(pTHX_ size_t size) {
120 SV *sv = sv_2mortal(newSV(size));
121
122 return SvPVX(sv);
123}
124
0aaa8b4d
TC
125static void *
126calloc_temp(pTHX_ size_t size) {
127 void *result = malloc_temp(aTHX_ size);
128 memset(result, 0, size);
129
130 return result;
131}
132
19e9591b 133/* for use with the T_AVARRAY typemap */
0aaa8b4d
TC
134#define doublePtr(size) ((double *)calloc_temp(aTHX_ sizeof(double) * (size)))
135#define SvDouble(sv, pname) (SvNV(sv))
136
137#define intPtr(size) ((int *)calloc_temp(aTHX_ sizeof(int) * (size)))
138#define SvInt(sv, pname) (SvIV(sv))
139
140#define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size)))
141#define SvI_img_dim(sv, pname) (SvIV(sv))
19e9591b 142
0aaa8b4d
TC
143#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size)))
144
145#define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname)
146
147static i_color
148S_sv_to_i_color(pTHX_ SV *sv, const char *pname) {
149 if (!sv_derived_from(sv, "Imager::Color")) {
b6565be6 150 croak("%s: not a color object", pname);
0aaa8b4d
TC
151 }
152 return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
153}
19e9591b 154
b33c08f8
TC
155/* These functions are all shared - then comes platform dependant code */
156static int getstr(void *hv_t,char *key,char **store) {
b13a3ddb 157 dTHX;
b33c08f8
TC
158 SV** svpp;
159 HV* hv=(HV*)hv_t;
160
8d14daab 161 mm_log((1,"getstr(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
162
163 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
164
165 svpp=hv_fetch(hv, key, strlen(key), 0);
166 *store=SvPV(*svpp, PL_na );
167
168 return 1;
169}
170
171static int getint(void *hv_t,char *key,int *store) {
b13a3ddb 172 dTHX;
b33c08f8
TC
173 SV** svpp;
174 HV* hv=(HV*)hv_t;
175
8d14daab 176 mm_log((1,"getint(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
177
178 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
179
180 svpp=hv_fetch(hv, key, strlen(key), 0);
181 *store=(int)SvIV(*svpp);
182 return 1;
183}
184
185static int getdouble(void *hv_t,char* key,double *store) {
b13a3ddb 186 dTHX;
b33c08f8
TC
187 SV** svpp;
188 HV* hv=(HV*)hv_t;
189
8d14daab 190 mm_log((1,"getdouble(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
191
192 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
193 svpp=hv_fetch(hv, key, strlen(key), 0);
8d14daab 194 *store=(double)SvNV(*svpp);
b33c08f8
TC
195 return 1;
196}
197
198static int getvoid(void *hv_t,char* key,void **store) {
b13a3ddb 199 dTHX;
b33c08f8
TC
200 SV** svpp;
201 HV* hv=(HV*)hv_t;
202
8d14daab 203 mm_log((1,"getvoid(hv_t %p, key %s, store %p)\n",hv_t,key,store));
b33c08f8
TC
204
205 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
206
207 svpp=hv_fetch(hv, key, strlen(key), 0);
208 *store = INT2PTR(void*, SvIV(*svpp));
209
210 return 1;
211}
212
213static int getobj(void *hv_t,char *key,char *type,void **store) {
b13a3ddb 214 dTHX;
b33c08f8
TC
215 SV** svpp;
216 HV* hv=(HV*)hv_t;
217
8d14daab 218 mm_log((1,"getobj(hv_t %p, key %s,type %s, store %p)\n",hv_t,key,type,store));
b33c08f8
TC
219
220 if ( !hv_exists(hv,key,strlen(key)) ) return 0;
221
222 svpp=hv_fetch(hv, key, strlen(key), 0);
223
224 if (sv_derived_from(*svpp,type)) {
225 IV tmp = SvIV((SV*)SvRV(*svpp));
226 *store = INT2PTR(void*, tmp);
227 } else {
228 mm_log((1,"getobj: key exists in hash but is not of correct type"));
229 return 0;
230 }
231
232 return 1;
233}
234
235UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
4dfa5522 236
a87997b2
TC
237static void
238free_buffer(void *p) {
239 myfree(p);
4dfa5522
AMH
240}
241
7f882a01 242
b33c08f8 243static void
bf1573f9 244i_log_entry(char *string, int level) {
b7506a07 245 mm_log((level, "%s", string));
7f882a01
AMH
246}
247
5e9a7fbd
TC
248static SV *
249make_i_color_sv(pTHX_ const i_color *c) {
250 SV *sv;
251 i_color *col = mymalloc(sizeof(i_color));
252 *col = *c;
253 sv = sv_newmortal();
254 sv_setref_pv(sv, "Imager::Color", (void *)col);
255
256 return sv;
257}
7f882a01 258
10461f9a
TC
259#define CBDATA_BUFSIZE 8192
260
261struct cbdata {
262 /* the SVs we use to call back to Perl */
263 SV *writecb;
264 SV *readcb;
265 SV *seekcb;
266 SV *closecb;
10461f9a
TC
267};
268
6d5c85a2
TC
269static ssize_t
270call_reader(struct cbdata *cbd, void *buf, size_t size,
271 size_t maxread) {
b13a3ddb 272 dTHX;
10461f9a
TC
273 int count;
274 int result;
275 SV *data;
276 dSP;
277
9d5ff8a6
TC
278 if (!SvOK(cbd->readcb)) {
279 mm_log((1, "read callback called but no readcb supplied\n"));
280 i_push_error(0, "read callback called but no readcb supplied");
10461f9a 281 return -1;
9d5ff8a6 282 }
10461f9a
TC
283
284 ENTER;
285 SAVETMPS;
286 EXTEND(SP, 2);
287 PUSHMARK(SP);
288 PUSHs(sv_2mortal(newSViv(size)));
289 PUSHs(sv_2mortal(newSViv(maxread)));
290 PUTBACK;
291
292 count = perl_call_sv(cbd->readcb, G_SCALAR);
293
294 SPAGAIN;
295
296 if (count != 1)
297 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
298
299 data = POPs;
300
301 if (SvOK(data)) {
302 STRLEN len;
6d5c85a2 303 char *ptr = SvPVbyte(data, len);
10461f9a 304 if (len > maxread)
6d5c85a2
TC
305 croak("Too much data returned in reader callback (wanted %d, got %d, expected %d)",
306 (int)size, (int)len, (int)maxread);
10461f9a
TC
307
308 memcpy(buf, ptr, len);
309 result = len;
310 }
311 else {
312 result = -1;
313 }
314
315 PUTBACK;
316 FREETMPS;
317 LEAVE;
318
319 return result;
320}
321
6d5c85a2
TC
322static off_t
323io_seeker(void *p, off_t offset, int whence) {
b13a3ddb 324 dTHX;
10461f9a
TC
325 struct cbdata *cbd = p;
326 int count;
327 off_t result;
328 dSP;
329
9d5ff8a6
TC
330 if (!SvOK(cbd->seekcb)) {
331 mm_log((1, "seek callback called but no seekcb supplied\n"));
332 i_push_error(0, "seek callback called but no seekcb supplied");
10461f9a 333 return -1;
9d5ff8a6 334 }
10461f9a 335
10461f9a
TC
336 ENTER;
337 SAVETMPS;
338 EXTEND(SP, 2);
339 PUSHMARK(SP);
340 PUSHs(sv_2mortal(newSViv(offset)));
341 PUSHs(sv_2mortal(newSViv(whence)));
342 PUTBACK;
343
344 count = perl_call_sv(cbd->seekcb, G_SCALAR);
345
346 SPAGAIN;
347
348 if (count != 1)
349 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
350
351 result = POPi;
352
353 PUTBACK;
354 FREETMPS;
355 LEAVE;
356
357 return result;
358}
359
6d5c85a2
TC
360static ssize_t
361io_writer(void *p, void const *data, size_t size) {
b13a3ddb 362 dTHX;
10461f9a 363 struct cbdata *cbd = p;
6d5c85a2
TC
364 I32 count;
365 SV *sv;
366 dSP;
367 bool success;
10461f9a 368
9d5ff8a6
TC
369 if (!SvOK(cbd->writecb)) {
370 mm_log((1, "write callback called but no writecb supplied\n"));
371 i_push_error(0, "write callback called but no writecb supplied");
6d5c85a2 372 return -1;
9d5ff8a6 373 }
6d5c85a2
TC
374
375 ENTER;
376 SAVETMPS;
377 EXTEND(SP, 1);
378 PUSHMARK(SP);
379 PUSHs(sv_2mortal(newSVpv((char *)data, size)));
380 PUTBACK;
381
382 count = perl_call_sv(cbd->writecb, G_SCALAR);
383
384 SPAGAIN;
385 if (count != 1)
386 croak("Result of perl_call_sv(..., G_SCALAR) != 1");
387
388 sv = POPs;
389 success = SvTRUE(sv);
390
391
392 PUTBACK;
393 FREETMPS;
394 LEAVE;
395
396 return success ? size : -1;
10461f9a
TC
397}
398
1f6c1c10
TC
399static ssize_t
400io_reader(void *p, void *data, size_t size) {
10461f9a 401 struct cbdata *cbd = p;
10461f9a 402
6d5c85a2 403 return call_reader(cbd, data, size, size);
10461f9a
TC
404}
405
2b405c9e 406static int io_closer(void *p) {
b13a3ddb 407 dTHX;
10461f9a 408 struct cbdata *cbd = p;
6d5c85a2 409 int success = 1;
10461f9a
TC
410
411 if (SvOK(cbd->closecb)) {
412 dSP;
6d5c85a2 413 I32 count;
10461f9a
TC
414
415 ENTER;
416 SAVETMPS;
417 PUSHMARK(SP);
418 PUTBACK;
419
6d5c85a2 420 count = perl_call_sv(cbd->closecb, G_SCALAR);
10461f9a
TC
421
422 SPAGAIN;
6d5c85a2 423
98747309
TC
424 if (count) {
425 SV *sv = POPs;
426 success = SvTRUE(sv);
427 }
428 else
429 success = 0;
6d5c85a2 430
10461f9a
TC
431 PUTBACK;
432 FREETMPS;
433 LEAVE;
434 }
2b405c9e 435
6d5c85a2 436 return success ? 0 : -1;
10461f9a
TC
437}
438
439static void io_destroyer(void *p) {
b13a3ddb 440 dTHX;
10461f9a
TC
441 struct cbdata *cbd = p;
442
443 SvREFCNT_dec(cbd->writecb);
444 SvREFCNT_dec(cbd->readcb);
445 SvREFCNT_dec(cbd->seekcb);
446 SvREFCNT_dec(cbd->closecb);
a4168bea 447 myfree(cbd);
10461f9a
TC
448}
449
a87997b2
TC
450static bool
451im_SvREFSCALAR(SV *sv) {
452 svtype type = SvTYPE(sv);
ea87cee9
TC
453
454 switch (type) {
455 case SVt_PV:
456 case SVt_PVIV:
457 case SVt_PVNV:
458 case SVt_PVMG:
459 case SVt_IV:
460 case SVt_NV:
461 case SVt_PVLV:
462#if PERL_VERSION > 10
463 case SVt_REGEXP:
464#endif
465 return 1;
466
467 default:
468 return 0;
469 }
470}
471
472static const char *
473describe_sv(SV *sv) {
474 if (SvOK(sv)) {
475 if (SvROK(sv)) {
476 svtype type = SvTYPE(SvRV(sv));
477 switch (type) {
478 case SVt_PVCV: return "CV";
479 case SVt_PVGV: return "GV";
480 case SVt_PVLV: return "LV";
481 default: return "some reference";
482 }
483 }
484 else {
485 return "non-reference scalar";
486 }
487 }
488 else {
489 return "undef";
490 }
a87997b2
TC
491}
492
6d5c85a2
TC
493static i_io_glue_t *
494do_io_new_buffer(pTHX_ SV *data_sv) {
495 const char *data;
a87997b2 496 char *data_copy;
6d5c85a2 497 STRLEN length;
a87997b2
TC
498 SV *sv;
499
500 SvGETMAGIC(data_sv);
501 if (SvROK(data_sv)) {
ea87cee9 502 if (im_SvREFSCALAR(SvRV(data_sv))) {
a87997b2
TC
503 sv = SvRV(data_sv);
504 }
505 else {
ea87cee9 506 i_push_errorf(0, "data is not a scalar or a reference to scalar");
a87997b2
TC
507 return NULL;
508 }
509 }
510 else {
511 sv = data_sv;
512 }
6d5c85a2 513
a87997b2
TC
514 /* previously this would keep the SV around, but this is unsafe in
515 many ways, so always copy the bytes */
516 data = SvPVbyte(sv, length);
517 data_copy = mymalloc(length);
518 memcpy(data_copy, data, length);
519 return io_new_buffer(data_copy, length, free_buffer, data_copy);
6d5c85a2
TC
520}
521
522static i_io_glue_t *
523do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
524 struct cbdata *cbd;
525
526 cbd = mymalloc(sizeof(struct cbdata));
527 cbd->writecb = newSVsv(writecb);
528 cbd->readcb = newSVsv(readcb);
529 cbd->seekcb = newSVsv(seekcb);
530 cbd->closecb = newSVsv(closecb);
531
9d5ff8a6
TC
532 mm_log((1, "do_io_new_cb(writecb %p (%s), readcb %p (%s), seekcb %p (%s), closecb %p (%s))\n", writecb, describe_sv(writecb), readcb, describe_sv(readcb), seekcb, describe_sv(seekcb), closecb, describe_sv(closecb)));
533
6d5c85a2
TC
534 return io_new_cb(cbd, io_reader, io_writer, io_seeker, io_closer,
535 io_destroyer);
536}
537
02d1d628
AMH
538struct value_name {
539 char *name;
540 int value;
541};
542static int lookup_name(struct value_name *names, int count, char *name, int def_value)
543{
544 int i;
545 for (i = 0; i < count; ++i)
546 if (strEQ(names[i].name, name))
547 return names[i].value;
548
549 return def_value;
550}
551static struct value_name transp_names[] =
552{
553 { "none", tr_none },
554 { "threshold", tr_threshold },
555 { "errdiff", tr_errdiff },
556 { "ordered", tr_ordered, },
557};
558
559static struct value_name make_color_names[] =
560{
561 { "none", mc_none, },
562 { "webmap", mc_web_map, },
563 { "addi", mc_addi, },
97c4effc 564 { "mediancut", mc_median_cut, },
9c106321
TC
565 { "mono", mc_mono, },
566 { "monochrome", mc_mono, },
5e9a7fbd
TC
567 { "gray", mc_gray, },
568 { "gray4", mc_gray4, },
569 { "gray16", mc_gray16, },
02d1d628
AMH
570};
571
572static struct value_name translate_names[] =
573{
02d1d628 574 { "giflib", pt_giflib, },
02d1d628
AMH
575 { "closest", pt_closest, },
576 { "perturb", pt_perturb, },
577 { "errdiff", pt_errdiff, },
578};
579
580static struct value_name errdiff_names[] =
581{
582 { "floyd", ed_floyd, },
583 { "jarvis", ed_jarvis, },
584 { "stucki", ed_stucki, },
585 { "custom", ed_custom, },
586};
587
588static struct value_name orddith_names[] =
589{
590 { "random", od_random, },
591 { "dot8", od_dot8, },
592 { "dot4", od_dot4, },
593 { "hline", od_hline, },
594 { "vline", od_vline, },
595 { "/line", od_slashline, },
596 { "slashline", od_slashline, },
597 { "\\line", od_backline, },
598 { "backline", od_backline, },
e7d4ea82 599 { "tiny", od_tiny, },
02d1d628
AMH
600 { "custom", od_custom, },
601};
602
603/* look through the hash for quantization options */
ec6d8908
TC
604static void
605ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
02d1d628
AMH
606{
607 /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
608 SV **sv;
609 int i;
610 STRLEN len;
611 char *str;
612
46a04ceb
TC
613 quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color));
614
02d1d628
AMH
615 sv = hv_fetch(hv, "transp", 6, 0);
616 if (sv && *sv && (str = SvPV(*sv, len))) {
617 quant->transp =
618 lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names),
619 str, tr_none);
620 if (quant->transp != tr_none) {
621 quant->tr_threshold = 127;
622 sv = hv_fetch(hv, "tr_threshold", 12, 0);
623 if (sv && *sv)
624 quant->tr_threshold = SvIV(*sv);
625 }
626 if (quant->transp == tr_errdiff) {
627 sv = hv_fetch(hv, "tr_errdiff", 10, 0);
628 if (sv && *sv && (str = SvPV(*sv, len)))
629 quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
630 }
631 if (quant->transp == tr_ordered) {
e7d4ea82 632 quant->tr_orddith = od_tiny;
02d1d628
AMH
633 sv = hv_fetch(hv, "tr_orddith", 10, 0);
634 if (sv && *sv && (str = SvPV(*sv, len)))
635 quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random);
636
637 if (quant->tr_orddith == od_custom) {
638 sv = hv_fetch(hv, "tr_map", 6, 0);
639 if (sv && *sv && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
640 AV *av = (AV*)SvRV(*sv);
641 len = av_len(av) + 1;
642 if (len > sizeof(quant->tr_custom))
643 len = sizeof(quant->tr_custom);
644 for (i = 0; i < len; ++i) {
645 SV **sv2 = av_fetch(av, i, 0);
646 if (sv2 && *sv2) {
647 quant->tr_custom[i] = SvIV(*sv2);
648 }
649 }
650 while (i < sizeof(quant->tr_custom))
651 quant->tr_custom[i++] = 0;
652 }
653 }
654 }
655 }
0348fe07 656 quant->make_colors = mc_median_cut;
02d1d628
AMH
657 sv = hv_fetch(hv, "make_colors", 11, 0);
658 if (sv && *sv && (str = SvPV(*sv, len))) {
659 quant->make_colors =
74de8638 660 lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut);
02d1d628
AMH
661 }
662 sv = hv_fetch(hv, "colors", 6, 0);
663 if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
664 /* needs to be an array of Imager::Color
665 note that the caller allocates the mc_color array and sets mc_size
666 to it's size */
667 AV *av = (AV *)SvRV(*sv);
668 quant->mc_count = av_len(av)+1;
669 if (quant->mc_count > quant->mc_size)
670 quant->mc_count = quant->mc_size;
671 for (i = 0; i < quant->mc_count; ++i) {
672 SV **sv1 = av_fetch(av, i, 0);
673 if (sv1 && *sv1 && SvROK(*sv1) && sv_derived_from(*sv1, "Imager::Color")) {
4c4c2ffd 674 i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1)));
02d1d628
AMH
675 quant->mc_colors[i] = *col;
676 }
677 }
678 }
679 sv = hv_fetch(hv, "max_colors", 10, 0);
680 if (sv && *sv) {
681 i = SvIV(*sv);
682 if (i <= quant->mc_size && i >= quant->mc_count)
683 quant->mc_size = i;
684 }
685
686 quant->translate = pt_closest;
687 sv = hv_fetch(hv, "translate", 9, 0);
688 if (sv && *sv && (str = SvPV(*sv, len))) {
689 quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest);
690 }
691 sv = hv_fetch(hv, "errdiff", 7, 0);
692 if (sv && *sv && (str = SvPV(*sv, len))) {
693 quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
694 }
695 if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) {
696 /* get the error diffusion map */
697 sv = hv_fetch(hv, "errdiff_width", 13, 0);
698 if (sv && *sv)
699 quant->ed_width = SvIV(*sv);
700 sv = hv_fetch(hv, "errdiff_height", 14, 0);
701 if (sv && *sv)
702 quant->ed_height = SvIV(*sv);
703 sv = hv_fetch(hv, "errdiff_orig", 12, 0);
704 if (sv && *sv)
705 quant->ed_orig = SvIV(*sv);
706 if (quant->ed_width > 0 && quant->ed_height > 0) {
707 int sum = 0;
708 quant->ed_map = mymalloc(sizeof(int)*quant->ed_width*quant->ed_height);
709 sv = hv_fetch(hv, "errdiff_map", 11, 0);
710 if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
711 AV *av = (AV*)SvRV(*sv);
712 len = av_len(av) + 1;
713 if (len > quant->ed_width * quant->ed_height)
714 len = quant->ed_width * quant->ed_height;
715 for (i = 0; i < len; ++i) {
716 SV **sv2 = av_fetch(av, i, 0);
717 if (sv2 && *sv2) {
718 quant->ed_map[i] = SvIV(*sv2);
719 sum += quant->ed_map[i];
720 }
721 }
722 }
723 if (!sum) {
724 /* broken map */
725 myfree(quant->ed_map);
726 quant->ed_map = 0;
727 quant->errdiff = ed_floyd;
728 }
729 }
730 }
731 sv = hv_fetch(hv, "perturb", 7, 0);
732 if (sv && *sv)
733 quant->perturb = SvIV(*sv);
734}
735
ec6d8908
TC
736static void
737ip_cleanup_quant_opts(pTHX_ i_quantize *quant) {
46a04ceb
TC
738 myfree(quant->mc_colors);
739 if (quant->ed_map)
740 myfree(quant->ed_map);
741}
742
02d1d628 743/* copies the color map from the hv into the colors member of the HV */
ec6d8908
TC
744static void
745ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
02d1d628
AMH
746 SV **sv;
747 AV *av;
748 int i;
749 SV *work;
750
751 sv = hv_fetch(hv, "colors", 6, 0);
752 if (!sv || !*sv || !SvROK(*sv) || SvTYPE(SvRV(*sv)) != SVt_PVAV) {
5c0d0ddf
TC
753 /* nothing to do */
754 return;
02d1d628 755 }
5c0d0ddf
TC
756
757 av = (AV *)SvRV(*sv);
758 av_clear(av);
02d1d628
AMH
759 av_extend(av, quant->mc_count+1);
760 for (i = 0; i < quant->mc_count; ++i) {
761 i_color *in = quant->mc_colors+i;
762 Imager__Color c = ICL_new_internal(in->rgb.r, in->rgb.g, in->rgb.b, 255);
763 work = sv_newmortal();
764 sv_setref_pv(work, "Imager::Color", (void *)c);
765 SvREFCNT_inc(work);
5c0d0ddf 766 av_push(av, work);
02d1d628
AMH
767 }
768}
769
f1ac5027 770/* loads the segments of a fountain fill into an array */
b33c08f8 771static i_fountain_seg *
b13a3ddb 772load_fount_segs(pTHX_ AV *asegs, int *count) {
f1ac5027
TC
773 /* Each element of segs must contain:
774 [ start, middle, end, c0, c1, segtype, colortrans ]
775 start, middle, end are doubles from 0 to 1
776 c0, c1 are Imager::Color::Float or Imager::Color objects
777 segtype, colortrans are ints
778 */
779 int i, j;
780 AV *aseg;
f1ac5027
TC
781 i_fountain_seg *segs;
782 double work[3];
783 int worki[2];
784
785 *count = av_len(asegs)+1;
786 if (*count < 1)
787 croak("i_fountain must have at least one segment");
788 segs = mymalloc(sizeof(i_fountain_seg) * *count);
789 for(i = 0; i < *count; i++) {
790 SV **sv1 = av_fetch(asegs, i, 0);
791 if (!sv1 || !*sv1 || !SvROK(*sv1)
792 || SvTYPE(SvRV(*sv1)) != SVt_PVAV) {
793 myfree(segs);
794 croak("i_fountain: segs must be an arrayref of arrayrefs");
795 }
796 aseg = (AV *)SvRV(*sv1);
797 if (av_len(aseg) != 7-1) {
798 myfree(segs);
799 croak("i_fountain: a segment must have 7 members");
800 }
801 for (j = 0; j < 3; ++j) {
802 SV **sv2 = av_fetch(aseg, j, 0);
803 if (!sv2 || !*sv2) {
804 myfree(segs);
805 croak("i_fountain: XS error");
806 }
807 work[j] = SvNV(*sv2);
808 }
809 segs[i].start = work[0];
810 segs[i].middle = work[1];
811 segs[i].end = work[2];
812 for (j = 0; j < 2; ++j) {
813 SV **sv3 = av_fetch(aseg, 3+j, 0);
814 if (!sv3 || !*sv3 || !SvROK(*sv3) ||
815 (!sv_derived_from(*sv3, "Imager::Color")
816 && !sv_derived_from(*sv3, "Imager::Color::Float"))) {
817 myfree(segs);
818 croak("i_fountain: segs must contain colors in elements 3 and 4");
819 }
820 if (sv_derived_from(*sv3, "Imager::Color::Float")) {
4c4c2ffd 821 segs[i].c[j] = *INT2PTR(i_fcolor *, SvIV((SV *)SvRV(*sv3)));
f1ac5027
TC
822 }
823 else {
4c4c2ffd 824 i_color c = *INT2PTR(i_color *, SvIV((SV *)SvRV(*sv3)));
f1ac5027
TC
825 int ch;
826 for (ch = 0; ch < MAXCHANNELS; ++ch) {
827 segs[i].c[j].channel[ch] = c.channel[ch] / 255.0;
828 }
829 }
830 }
831 for (j = 0; j < 2; ++j) {
832 SV **sv2 = av_fetch(aseg, j+5, 0);
833 if (!sv2 || !*sv2) {
834 myfree(segs);
835 croak("i_fountain: XS error");
836 }
837 worki[j] = SvIV(*sv2);
838 }
839 segs[i].type = worki[0];
840 segs[i].color = worki[1];
841 }
842
843 return segs;
844}
845
4cda4e76
TC
846/* validates the indexes supplied to i_ppal
847
848i_ppal() doesn't do that for speed, but I'm not comfortable doing that
849for calls from perl.
850
851*/
852static void
853validate_i_ppal(i_img *im, i_palidx const *indexes, int count) {
854 int color_count = i_colorcount(im);
855 int i;
856
857 if (color_count == -1)
858 croak("i_plin() called on direct color image");
859
860 for (i = 0; i < count; ++i) {
861 if (indexes[i] >= color_count) {
862 croak("i_plin() called with out of range color index %d (max %d)",
863 indexes[i], color_count-1);
864 }
865 }
866}
867
faa9b3e7
TC
868/* I don't think ICLF_* names belong at the C interface
869 this makes the XS code think we have them, to let us avoid
870 putting function bodies in the XS code
871*/
872#define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a))
873#define ICLF_DESTROY(cl) i_fcolor_destroy(cl)
874
10ea52a3
TC
875#ifdef IMAGER_LOG
876#define i_log_enabled() 1
877#else
878#define i_log_enabled() 0
879#endif
880
a8652edf
TC
881#if i_int_hlines_testing()
882
883typedef i_int_hlines *Imager__Internal__Hlines;
884
885static i_int_hlines *
8d14daab 886i_int_hlines_new(i_img_dim start_y, i_img_dim count_y, i_img_dim start_x, i_img_dim count_x) {
a8652edf
TC
887 i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
888 i_int_init_hlines(result, start_y, count_y, start_x, count_x);
889
890 return result;
891}
892
893static i_int_hlines *
894i_int_hlines_new_img(i_img *im) {
895 i_int_hlines *result = mymalloc(sizeof(i_int_hlines));
896 i_int_init_hlines_img(result, im);
897
898 return result;
899}
900
901static void
902i_int_hlines_DESTROY(i_int_hlines *hlines) {
903 i_int_hlines_destroy(hlines);
904 myfree(hlines);
905}
906
ffddd407
TC
907#define i_int_hlines_CLONE_SKIP(cls) 1
908
a8652edf
TC
909static int seg_compare(const void *vleft, const void *vright) {
910 const i_int_hline_seg *left = vleft;
911 const i_int_hline_seg *right = vright;
912
913 return left->minx - right->minx;
914}
915
916static SV *
917i_int_hlines_dump(i_int_hlines *hlines) {
b13a3ddb 918 dTHX;
8d14daab
TC
919 SV *dump = newSVpvf("start_y: %" i_DF " limit_y: %" i_DF " start_x: %" i_DF " limit_x: %" i_DF"\n",
920 i_DFc(hlines->start_y), i_DFc(hlines->limit_y), i_DFc(hlines->start_x), i_DFc(hlines->limit_x));
921 i_img_dim y;
a8652edf
TC
922
923 for (y = hlines->start_y; y < hlines->limit_y; ++y) {
924 i_int_hline_entry *entry = hlines->entries[y-hlines->start_y];
925 if (entry) {
926 int i;
927 /* sort the segments, if any */
928 if (entry->count)
929 qsort(entry->segs, entry->count, sizeof(i_int_hline_seg), seg_compare);
930
8d14daab 931 sv_catpvf(dump, " %" i_DF " (%" i_DF "):", i_DFc(y), i_DFc(entry->count));
a8652edf 932 for (i = 0; i < entry->count; ++i) {
8d14daab
TC
933 sv_catpvf(dump, " [%" i_DF ", %" i_DF ")", i_DFc(entry->segs[i].minx),
934 i_DFc(entry->segs[i].x_limit));
a8652edf
TC
935 }
936 sv_catpv(dump, "\n");
937 }
938 }
939
940 return dump;
941}
942
943#endif
944
8d14daab
TC
945static off_t
946i_sv_off_t(pTHX_ SV *sv) {
947#if LSEEKSIZE > IVSIZE
948 return (off_t)SvNV(sv);
949#else
950 return (off_t)SvIV(sv);
951#endif
952}
953
954static SV *
955i_new_sv_off_t(pTHX_ off_t off) {
956#if LSEEKSIZE > IVSIZE
957 return newSVnv(off);
958#else
959 return newSViv(off);
960#endif
961}
962
ec6d8908
TC
963static im_pl_ext_funcs im_perl_funcs =
964{
965 IMAGER_PL_API_VERSION,
966 IMAGER_PL_API_LEVEL,
967 ip_handle_quant_opts,
968 ip_cleanup_quant_opts,
969 ip_copy_colors_back
970};
971
972#define PERL_PL_SET_GLOBAL_CALLBACKS \
973 sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs));
974
bdd4c63b
TC
975#define IIM_new i_img_8_new
976#define IIM_DESTROY i_img_destroy
42505e61 977typedef int SysRet;
bdd4c63b 978
f7450478
TC
979#ifdef IMEXIF_ENABLE
980#define i_exif_enabled() 1
981#else
982#define i_exif_enabled() 0
983#endif
984
d16420e9 985/* trying to use more C style names, map them here */
eda1622c 986#define i_io_DESTROY(ig) io_glue_destroy(ig)
d16420e9 987
3b000586
TC
988#define i_img_get_width(im) ((im)->xsize)
989#define i_img_get_height(im) ((im)->ysize)
990
4498c8bd
TC
991#define i_img_epsilonf() (DBL_EPSILON * 4)
992
6d5c85a2
TC
993/* avoid some xsubpp strangeness */
994#define NEWLINE '\n'
995
02d1d628
AMH
996MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_
997
998Imager::Color
999ICL_new_internal(r,g,b,a)
1000 unsigned char r
1001 unsigned char g
1002 unsigned char b
1003 unsigned char a
1004
1005void
1006ICL_DESTROY(cl)
1007 Imager::Color cl
1008
1009
29106a11 1010void
02d1d628
AMH
1011ICL_set_internal(cl,r,g,b,a)
1012 Imager::Color cl
1013 unsigned char r
1014 unsigned char g
1015 unsigned char b
1016 unsigned char a
29106a11 1017 PPCODE:
46062ab6 1018 ICL_set_internal(cl, r, g, b, a);
29106a11
TC
1019 EXTEND(SP, 1);
1020 PUSHs(ST(0));
02d1d628
AMH
1021
1022void
1023ICL_info(cl)
1024 Imager::Color cl
1025
1026
1027void
1028ICL_rgba(cl)
1029 Imager::Color cl
1030 PPCODE:
1031 EXTEND(SP, 4);
b482243a
TC
1032 PUSHs(sv_2mortal(newSViv(cl->rgba.r)));
1033 PUSHs(sv_2mortal(newSViv(cl->rgba.g)));
1034 PUSHs(sv_2mortal(newSViv(cl->rgba.b)));
1035 PUSHs(sv_2mortal(newSViv(cl->rgba.a)));
02d1d628 1036
efdc2568
TC
1037Imager::Color
1038i_hsv_to_rgb(c)
1039 Imager::Color c
1040 CODE:
1041 RETVAL = mymalloc(sizeof(i_color));
1042 *RETVAL = *c;
1043 i_hsv_to_rgb(RETVAL);
1044 OUTPUT:
1045 RETVAL
1046
1047Imager::Color
1048i_rgb_to_hsv(c)
1049 Imager::Color c
1050 CODE:
1051 RETVAL = mymalloc(sizeof(i_color));
1052 *RETVAL = *c;
1053 i_rgb_to_hsv(RETVAL);
1054 OUTPUT:
1055 RETVAL
1056
02d1d628
AMH
1057
1058
faa9b3e7 1059MODULE = Imager PACKAGE = Imager::Color::Float PREFIX=ICLF_
02d1d628 1060
faa9b3e7
TC
1061Imager::Color::Float
1062ICLF_new_internal(r, g, b, a)
1063 double r
1064 double g
1065 double b
1066 double a
1067
1068void
1069ICLF_DESTROY(cl)
1070 Imager::Color::Float cl
02d1d628 1071
faa9b3e7
TC
1072void
1073ICLF_rgba(cl)
1074 Imager::Color::Float cl
1075 PREINIT:
1076 int ch;
1077 PPCODE:
1078 EXTEND(SP, MAXCHANNELS);
1079 for (ch = 0; ch < MAXCHANNELS; ++ch) {
1080 /* printf("%d: %g\n", ch, cl->channel[ch]); */
1081 PUSHs(sv_2mortal(newSVnv(cl->channel[ch])));
1082 }
1083
1084void
1085ICLF_set_internal(cl,r,g,b,a)
1086 Imager::Color::Float cl
1087 double r
1088 double g
1089 double b
1090 double a
1091 PPCODE:
1092 cl->rgba.r = r;
1093 cl->rgba.g = g;
1094 cl->rgba.b = b;
1095 cl->rgba.a = a;
1096 EXTEND(SP, 1);
1097 PUSHs(ST(0));
02d1d628 1098
efdc2568
TC
1099Imager::Color::Float
1100i_hsv_to_rgb(c)
1101 Imager::Color::Float c
1102 CODE:
1103 RETVAL = mymalloc(sizeof(i_fcolor));
1104 *RETVAL = *c;
1105 i_hsv_to_rgbf(RETVAL);
1106 OUTPUT:
1107 RETVAL
1108
1109Imager::Color::Float
1110i_rgb_to_hsv(c)
1111 Imager::Color::Float c
1112 CODE:
1113 RETVAL = mymalloc(sizeof(i_fcolor));
1114 *RETVAL = *c;
1115 i_rgb_to_hsvf(RETVAL);
1116 OUTPUT:
1117 RETVAL
efdc2568 1118
02d1d628
AMH
1119MODULE = Imager PACKAGE = Imager::ImgRaw PREFIX = IIM_
1120
1121Imager::ImgRaw
1122IIM_new(x,y,ch)
8d14daab
TC
1123 i_img_dim x
1124 i_img_dim y
02d1d628
AMH
1125 int ch
1126
1127void
1128IIM_DESTROY(im)
1129 Imager::ImgRaw im
1130
1131
1132
1133MODULE = Imager PACKAGE = Imager
1134
1135PROTOTYPES: ENABLE
1136
1137
1138Imager::IO
1139io_new_fd(fd)
1140 int fd
1141
1142Imager::IO
1143io_new_bufchain()
1144
1145
4dfa5522 1146Imager::IO
6d5c85a2
TC
1147io_new_buffer(data_sv)
1148 SV *data_sv
4dfa5522 1149 CODE:
a87997b2 1150 i_clear_error();
6d5c85a2 1151 RETVAL = do_io_new_buffer(aTHX_ data_sv);
a87997b2
TC
1152 if (!RETVAL)
1153 XSRETURN(0);
4dfa5522
AMH
1154 OUTPUT:
1155 RETVAL
10461f9a
TC
1156
1157Imager::IO
1158io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
1159 SV *writecb;
1160 SV *readcb;
1161 SV *seekcb;
1162 SV *closecb;
10461f9a 1163 CODE:
6d5c85a2 1164 RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
10461f9a
TC
1165 OUTPUT:
1166 RETVAL
4dfa5522 1167
6d5c85a2 1168SV *
02d1d628
AMH
1169io_slurp(ig)
1170 Imager::IO ig
1171 PREINIT:
1172 unsigned char* data;
4dfa5522 1173 size_t tlength;
6d5c85a2 1174 CODE:
02d1d628
AMH
1175 data = NULL;
1176 tlength = io_slurp(ig, &data);
6d5c85a2 1177 RETVAL = newSVpv((char *)data,tlength);
02d1d628 1178 myfree(data);
6d5c85a2
TC
1179 OUTPUT:
1180 RETVAL
02d1d628
AMH
1181
1182
77157728
TC
1183undef_int
1184i_set_image_file_limits(width, height, bytes)
8d14daab
TC
1185 i_img_dim width
1186 i_img_dim height
1187 size_t bytes
77157728
TC
1188
1189void
1190i_get_image_file_limits()
1191 PREINIT:
8d14daab
TC
1192 i_img_dim width, height;
1193 size_t bytes;
77157728
TC
1194 PPCODE:
1195 if (i_get_image_file_limits(&width, &height, &bytes)) {
1196 EXTEND(SP, 3);
1197 PUSHs(sv_2mortal(newSViv(width)));
1198 PUSHs(sv_2mortal(newSViv(height)));
8d14daab 1199 PUSHs(sv_2mortal(newSVuv(bytes)));
77157728
TC
1200 }
1201
e1558ffe
TC
1202bool
1203i_int_check_image_file_limits(width, height, channels, sample_size)
1204 i_img_dim width
1205 i_img_dim height
1206 int channels
1207 size_t sample_size
1208 PROTOTYPE: DISABLE
1209
6d5c85a2
TC
1210MODULE = Imager PACKAGE = Imager::IO PREFIX = io_
1211
1212Imager::IO
1213io_new_fd(class, fd)
1214 int fd
1215 CODE:
1216 RETVAL = io_new_fd(fd);
1217 OUTPUT:
1218 RETVAL
1219
1220Imager::IO
1221io_new_buffer(class, data_sv)
1222 SV *data_sv
1223 CODE:
a87997b2 1224 i_clear_error();
6d5c85a2 1225 RETVAL = do_io_new_buffer(aTHX_ data_sv);
a87997b2
TC
1226 if (!RETVAL)
1227 XSRETURN(0);
6d5c85a2
TC
1228 OUTPUT:
1229 RETVAL
1230
1231Imager::IO
1232io_new_cb(class, writecb, readcb, seekcb, closecb)
1233 SV *writecb;
1234 SV *readcb;
1235 SV *seekcb;
1236 SV *closecb;
1237 CODE:
1238 RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
1239 OUTPUT:
1240 RETVAL
1241
1242Imager::IO
1243io_new_bufchain(class)
1244 CODE:
1245 RETVAL = io_new_bufchain();
1246 OUTPUT:
1247 RETVAL
1248
52d990d6
TC
1249Imager::IO
1250io__new_perlio(class, io)
1251 PerlIO *io
1252 CODE:
1253 RETVAL = im_io_new_perlio(aTHX_ io);
1254 OUTPUT:
1255 RETVAL
1256
6d5c85a2
TC
1257SV *
1258io_slurp(class, ig)
1259 Imager::IO ig
1260 PREINIT:
1261 unsigned char* data;
1262 size_t tlength;
1263 CODE:
1264 data = NULL;
1265 tlength = io_slurp(ig, &data);
1266 RETVAL = newSVpv((char *)data,tlength);
1267 myfree(data);
1268 OUTPUT:
1269 RETVAL
1270
eda1622c
TC
1271MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_
1272
6d5c85a2
TC
1273IV
1274i_io_raw_write(ig, data_sv)
eda1622c
TC
1275 Imager::IO ig
1276 SV *data_sv
1277 PREINIT:
1278 void *data;
1279 STRLEN size;
1280 CODE:
40a88898 1281 data = SvPVbyte(data_sv, size);
6d5c85a2 1282 RETVAL = i_io_raw_write(ig, data, size);
eda1622c
TC
1283 OUTPUT:
1284 RETVAL
1285
1f6c1c10 1286void
6d5c85a2 1287i_io_raw_read(ig, buffer_sv, size)
eda1622c
TC
1288 Imager::IO ig
1289 SV *buffer_sv
8d14daab 1290 IV size
eda1622c
TC
1291 PREINIT:
1292 void *buffer;
8d14daab 1293 ssize_t result;
1f6c1c10
TC
1294 PPCODE:
1295 if (size <= 0)
6d5c85a2 1296 croak("size negative in call to i_io_raw_read()");
d1442cc4
TC
1297 /* prevent an undefined value warning if they supplied an
1298 undef buffer.
1299 Orginally conditional on !SvOK(), but this will prevent the
1300 downgrade from croaking */
1301 sv_setpvn(buffer_sv, "", 0);
1302#ifdef SvUTF8
1303 if (SvUTF8(buffer_sv))
1304 sv_utf8_downgrade(buffer_sv, FALSE);
1305#endif
eda1622c 1306 buffer = SvGROW(buffer_sv, size+1);
6d5c85a2 1307 result = i_io_raw_read(ig, buffer, size);
1f6c1c10
TC
1308 if (result >= 0) {
1309 SvCUR_set(buffer_sv, result);
1310 *SvEND(buffer_sv) = '\0';
1311 SvPOK_only(buffer_sv);
1312 EXTEND(SP, 1);
1313 PUSHs(sv_2mortal(newSViv(result)));
eda1622c 1314 }
1f6c1c10
TC
1315 ST(1) = buffer_sv;
1316 SvSETMAGIC(ST(1));
1317
1318void
6d5c85a2 1319i_io_raw_read2(ig, size)
1f6c1c10 1320 Imager::IO ig
8d14daab 1321 IV size
1f6c1c10
TC
1322 PREINIT:
1323 SV *buffer_sv;
1324 void *buffer;
8d14daab 1325 ssize_t result;
1f6c1c10
TC
1326 PPCODE:
1327 if (size <= 0)
1328 croak("size negative in call to i_io_read2()");
1329 buffer_sv = newSV(size);
1330 buffer = SvGROW(buffer_sv, size+1);
6d5c85a2 1331 result = i_io_raw_read(ig, buffer, size);
1f6c1c10 1332 if (result >= 0) {
eda1622c
TC
1333 SvCUR_set(buffer_sv, result);
1334 *SvEND(buffer_sv) = '\0';
1335 SvPOK_only(buffer_sv);
1f6c1c10
TC
1336 EXTEND(SP, 1);
1337 PUSHs(sv_2mortal(buffer_sv));
eda1622c 1338 }
1f6c1c10
TC
1339 else {
1340 /* discard it */
1341 SvREFCNT_dec(buffer_sv);
1342 }
eda1622c 1343
8d14daab 1344off_t
6d5c85a2 1345i_io_raw_seek(ig, position, whence)
eda1622c 1346 Imager::IO ig
8d14daab 1347 off_t position
eda1622c 1348 int whence
c3cc977e 1349
1f6c1c10 1350int
6d5c85a2 1351i_io_raw_close(ig)
eda1622c
TC
1352 Imager::IO ig
1353
1354void
1355i_io_DESTROY(ig)
c3cc977e
AMH
1356 Imager::IO ig
1357
ffddd407
TC
1358int
1359i_io_CLONE_SKIP(...)
1360 CODE:
8d14daab 1361 (void)items; /* avoid unused warning for XS variable */
ffddd407
TC
1362 RETVAL = 1;
1363 OUTPUT:
1364 RETVAL
1365
6d5c85a2
TC
1366int
1367i_io_getc(ig)
1368 Imager::IO ig
1369
1370int
1371i_io_putc(ig, c)
1372 Imager::IO ig
1373 int c
1374
1375int
1376i_io_close(ig)
1377 Imager::IO ig
1378
1379int
1380i_io_flush(ig)
1381 Imager::IO ig
1382
1383int
1384i_io_peekc(ig)
1385 Imager::IO ig
1386
1387int
1388i_io_seek(ig, off, whence)
1389 Imager::IO ig
1390 off_t off
1391 int whence
1392
1393void
1394i_io_peekn(ig, size)
1395 Imager::IO ig
1396 STRLEN size
1397 PREINIT:
1398 SV *buffer_sv;
1399 void *buffer;
1400 ssize_t result;
1401 PPCODE:
1402 buffer_sv = newSV(size+1);
1403 buffer = SvGROW(buffer_sv, size+1);
1404 result = i_io_peekn(ig, buffer, size);
1405 if (result >= 0) {
1406 SvCUR_set(buffer_sv, result);
1407 *SvEND(buffer_sv) = '\0';
1408 SvPOK_only(buffer_sv);
1409 EXTEND(SP, 1);
1410 PUSHs(sv_2mortal(buffer_sv));
1411 }
1412 else {
1413 /* discard it */
1414 SvREFCNT_dec(buffer_sv);
1415 }
1416
1417void
1418i_io_read(ig, buffer_sv, size)
1419 Imager::IO ig
1420 SV *buffer_sv
1421 IV size
1422 PREINIT:
1423 void *buffer;
1424 ssize_t result;
1425 PPCODE:
1426 if (size <= 0)
1427 croak("size negative in call to i_io_read()");
d1442cc4
TC
1428 /* prevent an undefined value warning if they supplied an
1429 undef buffer.
1430 Orginally conditional on !SvOK(), but this will prevent the
1431 downgrade from croaking */
1432 sv_setpvn(buffer_sv, "", 0);
1433#ifdef SvUTF8
1434 if (SvUTF8(buffer_sv))
1435 sv_utf8_downgrade(buffer_sv, FALSE);
1436#endif
6d5c85a2
TC
1437 buffer = SvGROW(buffer_sv, size+1);
1438 result = i_io_read(ig, buffer, size);
1439 if (result >= 0) {
1440 SvCUR_set(buffer_sv, result);
1441 *SvEND(buffer_sv) = '\0';
1442 SvPOK_only(buffer_sv);
1443 EXTEND(SP, 1);
1444 PUSHs(sv_2mortal(newSViv(result)));
1445 }
1446 ST(1) = buffer_sv;
1447 SvSETMAGIC(ST(1));
1448
1449void
1450i_io_read2(ig, size)
1451 Imager::IO ig
1452 STRLEN size
1453 PREINIT:
1454 SV *buffer_sv;
1455 void *buffer;
1456 ssize_t result;
1457 PPCODE:
1458 if (size == 0)
1459 croak("size zero in call to read2()");
1460 buffer_sv = newSV(size);
1461 buffer = SvGROW(buffer_sv, size+1);
1462 result = i_io_read(ig, buffer, size);
1463 if (result > 0) {
1464 SvCUR_set(buffer_sv, result);
1465 *SvEND(buffer_sv) = '\0';
1466 SvPOK_only(buffer_sv);
1467 EXTEND(SP, 1);
1468 PUSHs(sv_2mortal(buffer_sv));
1469 }
1470 else {
1471 /* discard it */
1472 SvREFCNT_dec(buffer_sv);
1473 }
1474
1475void
1476i_io_gets(ig, size = 8192, eol = NEWLINE)
1477 Imager::IO ig
1478 STRLEN size
1479 int eol
1480 PREINIT:
1481 SV *buffer_sv;
1482 void *buffer;
1483 ssize_t result;
1484 PPCODE:
1485 if (size < 2)
1486 croak("size too small in call to gets()");
1487 buffer_sv = sv_2mortal(newSV(size+1));
1488 buffer = SvPVX(buffer_sv);
1489 result = i_io_gets(ig, buffer, size+1, eol);
1490 if (result > 0) {
1491 SvCUR_set(buffer_sv, result);
1492 *SvEND(buffer_sv) = '\0';
1493 SvPOK_only(buffer_sv);
1494 EXTEND(SP, 1);
1495 PUSHs(buffer_sv);
1496 }
1497
1498IV
1499i_io_write(ig, data_sv)
1500 Imager::IO ig
1501 SV *data_sv
1502 PREINIT:
1503 void *data;
1504 STRLEN size;
1505 CODE:
40a88898 1506 data = SvPVbyte(data_sv, size);
6d5c85a2
TC
1507 RETVAL = i_io_write(ig, data, size);
1508 OUTPUT:
1509 RETVAL
1510
1511void
1512i_io_dump(ig, flags = I_IO_DUMP_DEFAULT)
1513 Imager::IO ig
1514 int flags
1515
1516bool
1517i_io_set_buffered(ig, flag = 1)
1518 Imager::IO ig
1519 int flag
1520
1521bool
1522i_io_is_buffered(ig)
1523 Imager::IO ig
1524
1525bool
1526i_io_eof(ig)
1527 Imager::IO ig
1528
1529bool
1530i_io_error(ig)
1531 Imager::IO ig
1532
c3cc977e
AMH
1533MODULE = Imager PACKAGE = Imager
1534
1535PROTOTYPES: ENABLE
1536
02d1d628
AMH
1537void
1538i_list_formats()
1539 PREINIT:
1540 char* item;
1541 int i;
1542 PPCODE:
1543 i=0;
1544 while( (item=i_format_list[i++]) != NULL ) {
1545 EXTEND(SP, 1);
1546 PUSHs(sv_2mortal(newSVpv(item,0)));
1547 }
1548
ec76939c
TC
1549Imager::ImgRaw
1550i_sametype(im, x, y)
1551 Imager::ImgRaw im
8d14daab
TC
1552 i_img_dim x
1553 i_img_dim y
ec76939c
TC
1554
1555Imager::ImgRaw
1556i_sametype_chans(im, x, y, channels)
1557 Imager::ImgRaw im
8d14daab
TC
1558 i_img_dim x
1559 i_img_dim y
ec76939c
TC
1560 int channels
1561
10ea52a3 1562int
bd8052a6
TC
1563i_init_log(name_sv,level)
1564 SV* name_sv
02d1d628 1565 int level
bd8052a6
TC
1566 PREINIT:
1567 const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL;
1568 CODE:
10ea52a3
TC
1569 RETVAL = i_init_log(name, level);
1570 OUTPUT:
1571 RETVAL
02d1d628 1572
7f882a01 1573void
bf1573f9 1574i_log_entry(string,level)
7f882a01
AMH
1575 char* string
1576 int level
1577
10ea52a3
TC
1578int
1579i_log_enabled()
7f882a01 1580
02d1d628
AMH
1581void
1582i_img_info(im)
1583 Imager::ImgRaw im
1584 PREINIT:
8d14daab 1585 i_img_dim info[4];
02d1d628
AMH
1586 PPCODE:
1587 i_img_info(im,info);
1588 EXTEND(SP, 4);
1589 PUSHs(sv_2mortal(newSViv(info[0])));
1590 PUSHs(sv_2mortal(newSViv(info[1])));
1591 PUSHs(sv_2mortal(newSViv(info[2])));
1592 PUSHs(sv_2mortal(newSViv(info[3])));
1593
1594
1595
1596
1597void
1598i_img_setmask(im,ch_mask)
1599 Imager::ImgRaw im
1600 int ch_mask
1601
1602int
1603i_img_getmask(im)
1604 Imager::ImgRaw im
1605
1606int
1607i_img_getchannels(im)
1608 Imager::ImgRaw im
1609
1610void
1611i_img_getdata(im)
1612 Imager::ImgRaw im
1613 PPCODE:
1614 EXTEND(SP, 1);
26fd367b
TC
1615 PUSHs(im->idata ?
1616 sv_2mortal(newSVpv((char *)im->idata, im->bytes))
faa9b3e7 1617 : &PL_sv_undef);
02d1d628 1618
3b000586
TC
1619IV
1620i_img_get_width(im)
1621 Imager::ImgRaw im
1622
1623IV
1624i_img_get_height(im)
1625 Imager::ImgRaw im
1626
1627
bd8052a6
TC
1628void
1629i_img_is_monochrome(im)
1630 Imager::ImgRaw im
1631 PREINIT:
1632 int zero_is_white;
1633 int result;
1634 PPCODE:
1635 result = i_img_is_monochrome(im, &zero_is_white);
1636 if (result) {
1637 if (GIMME_V == G_ARRAY) {
1638 EXTEND(SP, 2);
1639 PUSHs(&PL_sv_yes);
1640 PUSHs(sv_2mortal(newSViv(zero_is_white)));
1641 }
1642 else {
1643 EXTEND(SP, 1);
1644 PUSHs(&PL_sv_yes);
1645 }
1646 }
02d1d628
AMH
1647
1648void
aa833c97 1649i_line(im,x1,y1,x2,y2,val,endp)
02d1d628 1650 Imager::ImgRaw im
8d14daab
TC
1651 i_img_dim x1
1652 i_img_dim y1
1653 i_img_dim x2
1654 i_img_dim y2
02d1d628 1655 Imager::Color val
aa833c97 1656 int endp
02d1d628
AMH
1657
1658void
b437ce0a 1659i_line_aa(im,x1,y1,x2,y2,val,endp)
02d1d628 1660 Imager::ImgRaw im
8d14daab
TC
1661 i_img_dim x1
1662 i_img_dim y1
1663 i_img_dim x2
1664 i_img_dim y2
02d1d628 1665 Imager::Color val
b437ce0a 1666 int endp
02d1d628
AMH
1667
1668void
1669i_box(im,x1,y1,x2,y2,val)
1670 Imager::ImgRaw im
8d14daab
TC
1671 i_img_dim x1
1672 i_img_dim y1
1673 i_img_dim x2
1674 i_img_dim y2
02d1d628
AMH
1675 Imager::Color val
1676
1677void
1678i_box_filled(im,x1,y1,x2,y2,val)
1679 Imager::ImgRaw im
8d14daab
TC
1680 i_img_dim x1
1681 i_img_dim y1
1682 i_img_dim x2
1683 i_img_dim y2
02d1d628
AMH
1684 Imager::Color val
1685
7477ff14
TC
1686int
1687i_box_filledf(im,x1,y1,x2,y2,val)
1688 Imager::ImgRaw im
8d14daab
TC
1689 i_img_dim x1
1690 i_img_dim y1
1691 i_img_dim x2
1692 i_img_dim y2
7477ff14
TC
1693 Imager::Color::Float val
1694
f1ac5027
TC
1695void
1696i_box_cfill(im,x1,y1,x2,y2,fill)
1697 Imager::ImgRaw im
8d14daab
TC
1698 i_img_dim x1
1699 i_img_dim y1
1700 i_img_dim x2
1701 i_img_dim y2
f1ac5027
TC
1702 Imager::FillHandle fill
1703
02d1d628
AMH
1704void
1705i_arc(im,x,y,rad,d1,d2,val)
1706 Imager::ImgRaw im
8d14daab
TC
1707 i_img_dim x
1708 i_img_dim y
1709 double rad
1710 double d1
1711 double d2
02d1d628
AMH
1712 Imager::Color val
1713
a8652edf
TC
1714void
1715i_arc_aa(im,x,y,rad,d1,d2,val)
1716 Imager::ImgRaw im
1717 double x
1718 double y
1719 double rad
1720 double d1
1721 double d2
1722 Imager::Color val
1723
f1ac5027
TC
1724void
1725i_arc_cfill(im,x,y,rad,d1,d2,fill)
1726 Imager::ImgRaw im
8d14daab
TC
1727 i_img_dim x
1728 i_img_dim y
1729 double rad
1730 double d1
1731 double d2
f1ac5027
TC
1732 Imager::FillHandle fill
1733
a8652edf
TC
1734void
1735i_arc_aa_cfill(im,x,y,rad,d1,d2,fill)
1736 Imager::ImgRaw im
1737 double x
1738 double y
1739 double rad
1740 double d1
1741 double d2
1742 Imager::FillHandle fill
02d1d628
AMH
1743
1744
6af18d2b
AMH
1745void
1746i_circle_aa(im,x,y,rad,val)
1747 Imager::ImgRaw im
8d14daab
TC
1748 double x
1749 double y
1750 double rad
6af18d2b
AMH
1751 Imager::Color val
1752
bf18ef3a
TC
1753void
1754i_circle_aa_fill(im,x,y,rad,fill)
1755 Imager::ImgRaw im
1756 double x
1757 double y
1758 double rad
1759 Imager::FillHandle fill
1760
40068b33
TC
1761int
1762i_circle_out(im,x,y,rad,val)
1763 Imager::ImgRaw im
1764 i_img_dim x
1765 i_img_dim y
1766 i_img_dim rad
1767 Imager::Color val
1768
1769int
1770i_circle_out_aa(im,x,y,rad,val)
1771 Imager::ImgRaw im
1772 i_img_dim x
1773 i_img_dim y
1774 i_img_dim rad
1775 Imager::Color val
1776
1777int
1778i_arc_out(im,x,y,rad,d1,d2,val)
1779 Imager::ImgRaw im
1780 i_img_dim x
1781 i_img_dim y
1782 i_img_dim rad
8d14daab
TC
1783 double d1
1784 double d2
40068b33
TC
1785 Imager::Color val
1786
1787int
1788i_arc_out_aa(im,x,y,rad,d1,d2,val)
1789 Imager::ImgRaw im
1790 i_img_dim x
1791 i_img_dim y
1792 i_img_dim rad
8d14daab
TC
1793 double d1
1794 double d2
40068b33 1795 Imager::Color val
6af18d2b
AMH
1796
1797
02d1d628 1798void
987245e2 1799i_bezier_multi(im,x,y,val)
02d1d628 1800 Imager::ImgRaw im
987245e2
TC
1801 double *x
1802 double *y
1803 Imager::Color val
1804 PREINIT:
1805 STRLEN size_x;
1806 STRLEN size_y;
1807 PPCODE:
1808 if (size_x != size_y)
1809 croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
1810 i_bezier_multi(im,size_x,x,y,val);
02d1d628 1811
1c5252ed 1812int
19e9591b 1813i_poly_aa(im,x,y,val)
02d1d628 1814 Imager::ImgRaw im
19e9591b
TC
1815 double *x
1816 double *y
a54e32ba
TC
1817 Imager::Color val
1818 PREINIT:
19e9591b
TC
1819 STRLEN size_x;
1820 STRLEN size_y;
a54e32ba 1821 CODE:
19e9591b 1822 if (size_x != size_y)
a54e32ba 1823 croak("Imager: x and y arrays to i_poly_aa must be equal length\n");
19e9591b 1824 RETVAL = i_poly_aa(im, size_x, x, y, val);
a54e32ba
TC
1825 OUTPUT:
1826 RETVAL
02d1d628 1827
1c5252ed 1828int
19e9591b 1829i_poly_aa_cfill(im, x, y, fill)
43c5dacb 1830 Imager::ImgRaw im
19e9591b
TC
1831 double *x
1832 double *y
a54e32ba
TC
1833 Imager::FillHandle fill
1834 PREINIT:
19e9591b
TC
1835 STRLEN size_x;
1836 STRLEN size_y;
a54e32ba 1837 CODE:
19e9591b 1838 if (size_x != size_y)
a54e32ba 1839 croak("Imager: x and y arrays to i_poly_aa_cfill must be equal length\n");
19e9591b 1840 RETVAL = i_poly_aa_cfill(im, size_x, x, y, fill);
a54e32ba
TC
1841 OUTPUT:
1842 RETVAL
02d1d628 1843
a321d497 1844undef_int
02d1d628
AMH
1845i_flood_fill(im,seedx,seedy,dcol)
1846 Imager::ImgRaw im
8d14daab
TC
1847 i_img_dim seedx
1848 i_img_dim seedy
02d1d628
AMH
1849 Imager::Color dcol
1850
a321d497 1851undef_int
cc6483e0
TC
1852i_flood_cfill(im,seedx,seedy,fill)
1853 Imager::ImgRaw im
8d14daab
TC
1854 i_img_dim seedx
1855 i_img_dim seedy
cc6483e0
TC
1856 Imager::FillHandle fill
1857
3efb0915
TC
1858undef_int
1859i_flood_fill_border(im,seedx,seedy,dcol, border)
1860 Imager::ImgRaw im
8d14daab
TC
1861 i_img_dim seedx
1862 i_img_dim seedy
3efb0915
TC
1863 Imager::Color dcol
1864 Imager::Color border
1865
1866undef_int
1867i_flood_cfill_border(im,seedx,seedy,fill, border)
1868 Imager::ImgRaw im
8d14daab
TC
1869 i_img_dim seedx
1870 i_img_dim seedy
3efb0915
TC
1871 Imager::FillHandle fill
1872 Imager::Color border
1873
02d1d628
AMH
1874
1875void
1876i_copyto(im,src,x1,y1,x2,y2,tx,ty)
1877 Imager::ImgRaw im
1878 Imager::ImgRaw src
8d14daab
TC
1879 i_img_dim x1
1880 i_img_dim y1
1881 i_img_dim x2
1882 i_img_dim y2
1883 i_img_dim tx
1884 i_img_dim ty
02d1d628
AMH
1885
1886
1887void
1888i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans)
1889 Imager::ImgRaw im
1890 Imager::ImgRaw src
8d14daab
TC
1891 i_img_dim x1
1892 i_img_dim y1
1893 i_img_dim x2
1894 i_img_dim y2
1895 i_img_dim tx
1896 i_img_dim ty
02d1d628
AMH
1897 Imager::Color trans
1898
92bda632
TC
1899Imager::ImgRaw
1900i_copy(src)
02d1d628
AMH
1901 Imager::ImgRaw src
1902
1903
faa9b3e7 1904undef_int
71dc4a83 1905i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy)
02d1d628
AMH
1906 Imager::ImgRaw im
1907 Imager::ImgRaw src
8d14daab
TC
1908 i_img_dim tx
1909 i_img_dim ty
1910 i_img_dim src_minx
1911 i_img_dim src_miny
1912 i_img_dim src_maxx
1913 i_img_dim src_maxy
71dc4a83 1914
9b1ec2b8
TC
1915undef_int
1916i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0)
1917 Imager::ImgRaw out
1918 Imager::ImgRaw src
8d14daab
TC
1919 i_img_dim out_left
1920 i_img_dim out_top
1921 i_img_dim src_left
1922 i_img_dim src_top
1923 i_img_dim width
1924 i_img_dim height
9b1ec2b8
TC
1925 int combine
1926 double opacity
1927
1928undef_int
1929i_compose_mask(out, src, mask, out_left, out_top, src_left, src_top, mask_left, mask_top, width, height, combine = ic_normal, opacity = 0.0)
1930 Imager::ImgRaw out
1931 Imager::ImgRaw src
1932 Imager::ImgRaw mask
8d14daab
TC
1933 i_img_dim out_left
1934 i_img_dim out_top
1935 i_img_dim src_left
1936 i_img_dim src_top
1937 i_img_dim mask_left
1938 i_img_dim mask_top
1939 i_img_dim width
1940 i_img_dim height
9b1ec2b8
TC
1941 int combine
1942 double opacity
02d1d628 1943
b47464c1
TC
1944Imager::ImgRaw
1945i_combine(src_av, channels_av = NULL)
1946 AV *src_av
1947 AV *channels_av
1948 PREINIT:
1949 i_img **imgs = NULL;
1950 STRLEN in_count;
1951 int *channels = NULL;
1952 int i;
1953 SV **psv;
1954 IV tmp;
1955 CODE:
1956 in_count = av_len(src_av) + 1;
1957 if (in_count > 0) {
1958 imgs = mymalloc(sizeof(i_img*) * in_count);
1959 channels = mymalloc(sizeof(int) * in_count);
1960 for (i = 0; i < in_count; ++i) {
1961 psv = av_fetch(src_av, i, 0);
1962 if (!psv || !*psv || !sv_derived_from(*psv, "Imager::ImgRaw")) {
1963 myfree(imgs);
1964 myfree(channels);
1965 croak("imgs must contain only images");
1966 }
1967 tmp = SvIV((SV*)SvRV(*psv));
1968 imgs[i] = INT2PTR(i_img*, tmp);
1969 if (channels_av &&
1970 (psv = av_fetch(channels_av, i, 0)) != NULL &&
1971 *psv) {
1972 channels[i] = SvIV(*psv);
1973 }
1974 else {
1975 channels[i] = 0;
1976 }
1977 }
1978 }
1979 RETVAL = i_combine(imgs, channels, in_count);
1980 myfree(imgs);
1981 myfree(channels);
1982 OUTPUT:
1983 RETVAL
1984
142c26ff
AMH
1985undef_int
1986i_flipxy(im, direction)
1987 Imager::ImgRaw im
1988 int direction
1989
faa9b3e7
TC
1990Imager::ImgRaw
1991i_rotate90(im, degrees)
1992 Imager::ImgRaw im
1993 int degrees
1994
1995Imager::ImgRaw
0d3b936e 1996i_rotate_exact(im, amount, ...)
faa9b3e7
TC
1997 Imager::ImgRaw im
1998 double amount
0d3b936e
TC
1999 PREINIT:
2000 i_color *backp = NULL;
2001 i_fcolor *fbackp = NULL;
2002 int i;
2003 SV * sv1;
2004 CODE:
2005 /* extract the bg colors if any */
2006 /* yes, this is kind of strange */
2007 for (i = 2; i < items; ++i) {
2008 sv1 = ST(i);
2009 if (sv_derived_from(sv1, "Imager::Color")) {
2010 IV tmp = SvIV((SV*)SvRV(sv1));
2011 backp = INT2PTR(i_color *, tmp);
2012 }
2013 else if (sv_derived_from(sv1, "Imager::Color::Float")) {
2014 IV tmp = SvIV((SV*)SvRV(sv1));
2015 fbackp = INT2PTR(i_fcolor *, tmp);
2016 }
2017 }
2018 RETVAL = i_rotate_exact_bg(im, amount, backp, fbackp);
2019 OUTPUT:
2020 RETVAL
faa9b3e7
TC
2021
2022Imager::ImgRaw
87b3f212 2023i_matrix_transform(im, xsize, ysize, matrix_av, ...)
faa9b3e7 2024 Imager::ImgRaw im
487ec752
TC
2025 i_img_dim xsize
2026 i_img_dim ysize
87b3f212 2027 AV *matrix_av
487ec752
TC
2028 PREINIT:
2029 double matrix[9];
2030 STRLEN len;
2031 SV *sv1;
2032 int i;
2033 i_color *backp = NULL;
2034 i_fcolor *fbackp = NULL;
2035 CODE:
2036 len=av_len(matrix_av)+1;
2037 if (len > 9)
2038 len = 9;
2039 for (i = 0; i < len; ++i) {
2040 sv1=(*(av_fetch(matrix_av,i,0)));
2041 matrix[i] = SvNV(sv1);
2042 }
2043 for (; i < 9; ++i)
2044 matrix[i] = 0;
2045 /* extract the bg colors if any */
2046 /* yes, this is kind of strange */
2047 for (i = 4; i < items; ++i) {
2048 sv1 = ST(i);
2049 if (sv_derived_from(sv1, "Imager::Color")) {
2050 IV tmp = SvIV((SV*)SvRV(sv1));
2051 backp = INT2PTR(i_color *, tmp);
2052 }
2053 else if (sv_derived_from(sv1, "Imager::Color::Float")) {
2054 IV tmp = SvIV((SV*)SvRV(sv1));
2055 fbackp = INT2PTR(i_fcolor *, tmp);
2056 }
2057 }
2058 RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp);
2059 OUTPUT:
2060 RETVAL
02d1d628 2061
167660cd 2062undef_int
02d1d628
AMH
2063i_gaussian(im,stdev)
2064 Imager::ImgRaw im
167660cd 2065 double stdev
02d1d628 2066
b6381851
TC
2067void
2068i_unsharp_mask(im,stdev,scale)
2069 Imager::ImgRaw im
8d14daab 2070 double stdev
b6381851
TC
2071 double scale
2072
6a3cbaef
TC
2073int
2074i_conv(im,coef)
2075 Imager::ImgRaw im
2076 AV *coef
2077 PREINIT:
2078 double* c_coef;
2079 int len;
2080 SV* sv1;
2081 int i;
2082 CODE:
2083 len = av_len(coef) + 1;
2084 c_coef=mymalloc( len * sizeof(double) );
2085 for(i = 0; i < len; i++) {
2086 sv1 = (*(av_fetch(coef, i, 0)));
2087 c_coef[i] = (double)SvNV(sv1);
2088 }
2089 RETVAL = i_conv(im, c_coef, len);
2090 myfree(c_coef);
2091 OUTPUT:
2092 RETVAL
02d1d628 2093
d5477d3d
TC
2094Imager::ImgRaw
2095i_convert(src, avmain)
f5991c03 2096 Imager::ImgRaw src
d5477d3d 2097 AV *avmain
f5991c03 2098 PREINIT:
62869327 2099 double *coeff;
f5991c03
TC
2100 int outchan;
2101 int inchan;
f5991c03 2102 SV **temp;
f5991c03
TC
2103 AV *avsub;
2104 int len;
2105 int i, j;
2106 CODE:
f5991c03
TC
2107 outchan = av_len(avmain)+1;
2108 /* find the biggest */
2109 inchan = 0;
2110 for (j=0; j < outchan; ++j) {
2111 temp = av_fetch(avmain, j, 0);
2112 if (temp && SvROK(*temp) && SvTYPE(SvRV(*temp)) == SVt_PVAV) {
2113 avsub = (AV*)SvRV(*temp);
2114 len = av_len(avsub)+1;
2115 if (len > inchan)
2116 inchan = len;
2117 }
26eb06dd
TC
2118 else {
2119 i_push_errorf(0, "invalid matrix: element %d is not an array ref", j);
2120 XSRETURN(0);
2121 }
f5991c03 2122 }
62869327 2123 coeff = mymalloc(sizeof(double) * outchan * inchan);
f5991c03
TC
2124 for (j = 0; j < outchan; ++j) {
2125 avsub = (AV*)SvRV(*av_fetch(avmain, j, 0));
2126 len = av_len(avsub)+1;
2127 for (i = 0; i < len; ++i) {
2128 temp = av_fetch(avsub, i, 0);
2129 if (temp)
2130 coeff[i+j*inchan] = SvNV(*temp);
2131 else
2132 coeff[i+j*inchan] = 0;
2133 }
2134 while (i < inchan)
2135 coeff[i++ + j*inchan] = 0;
2136 }
d5477d3d 2137 RETVAL = i_convert(src, coeff, outchan, inchan);
f5991c03 2138 myfree(coeff);
f5991c03
TC
2139 OUTPUT:
2140 RETVAL
40eba1ea
AMH
2141
2142
1136f089 2143undef_int
85f38e13 2144i_map(im, pmaps_av)
40eba1ea 2145 Imager::ImgRaw im
85f38e13 2146 AV *pmaps_av
64655904
TC
2147 PREINIT:
2148 unsigned int mask = 0;
64655904
TC
2149 AV *avsub;
2150 SV **temp;
2151 int len;
2152 int i, j;
2153 unsigned char (*maps)[256];
2154 CODE:
2155 len = av_len(pmaps_av)+1;
2156 if (im->channels < len)
2157 len = im->channels;
2158 maps = mymalloc( len * sizeof(unsigned char [256]) );
2159 for (j=0; j<len ; j++) {
2160 temp = av_fetch(pmaps_av, j, 0);
2161 if (temp && SvROK(*temp) && (SvTYPE(SvRV(*temp)) == SVt_PVAV) ) {
2162 avsub = (AV*)SvRV(*temp);
2163 if(av_len(avsub) != 255)
2164 continue;
2165 mask |= 1<<j;
2166 for (i=0; i<256 ; i++) {
2167 int val;
2168 temp = av_fetch(avsub, i, 0);
2169 val = temp ? SvIV(*temp) : 0;
2170 if (val<0) val = 0;
2171 if (val>255) val = 255;
2172 maps[j][i] = val;
2173 }
2174 }
2175 }
2176 i_map(im, maps, mask);
2177 myfree(maps);
2178 RETVAL = 1;
2179 OUTPUT:
2180 RETVAL
40eba1ea 2181
02d1d628
AMH
2182float
2183i_img_diff(im1,im2)
2184 Imager::ImgRaw im1
2185 Imager::ImgRaw im2
2186
e41cfe8f
TC
2187double
2188i_img_diffd(im1,im2)
2189 Imager::ImgRaw im1
2190 Imager::ImgRaw im2
02d1d628 2191
4498c8bd
TC
2192int
2193i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL)
2194 Imager::ImgRaw im1
2195 Imager::ImgRaw im2
2196 double epsilon
2197 const char *what
2198
2199double
2200i_img_epsilonf()
2201
813d4d0a
TC
2202bool
2203_is_color_object(sv)
2204 SV* sv
2205 CODE:
2206 SvGETMAGIC(sv);
2207 RETVAL = SvOK(sv) && SvROK(sv) &&
2208 (sv_derived_from(sv, "Imager::Color")
2209 || sv_derived_from(sv, "Imager::Color::Float"));
2210 OUTPUT:
2211 RETVAL
2212
02d1d628
AMH
2213#ifdef HAVE_LIBTT
2214
2215
4b19f77a 2216Imager::Font::TT
02d1d628
AMH
2217i_tt_new(fontname)
2218 char* fontname
2219
4b19f77a
AMH
2220
2221MODULE = Imager PACKAGE = Imager::Font::TT PREFIX=TT_
2222
2223#define TT_DESTROY(handle) i_tt_destroy(handle)
2224
02d1d628 2225void
4b19f77a
AMH
2226TT_DESTROY(handle)
2227 Imager::Font::TT handle
2228
ffddd407
TC
2229int
2230TT_CLONE_SKIP(...)
2231 CODE:
8d14daab 2232 (void)items; /* avoid unused warning */
ffddd407
TC
2233 RETVAL = 1;
2234 OUTPUT:
2235 RETVAL
2236
02d1d628 2237
4b19f77a 2238MODULE = Imager PACKAGE = Imager
02d1d628
AMH
2239
2240
2241undef_int
e3b4d6c3 2242i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1)
4b19f77a 2243 Imager::Font::TT handle
02d1d628 2244 Imager::ImgRaw im
8d14daab
TC
2245 i_img_dim xb
2246 i_img_dim yb
02d1d628 2247 Imager::Color cl
8d14daab 2248 double points
4f68b48f 2249 SV * str_sv
02d1d628 2250 int smooth
4f68b48f 2251 int utf8
9ab6338b 2252 int align
4f68b48f
TC
2253 PREINIT:
2254 char *str;
2255 STRLEN len;
2256 CODE:
e3b4d6c3 2257 str = SvPV(str_sv, len);
4f68b48f
TC
2258#ifdef SvUTF8
2259 if (SvUTF8(str_sv))
2260 utf8 = 1;
2261#endif
4f68b48f 2262 RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str,
9ab6338b 2263 len, smooth, utf8, align);
4f68b48f
TC
2264 OUTPUT:
2265 RETVAL
02d1d628
AMH
2266
2267
2268undef_int
e3b4d6c3 2269i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1)
4b19f77a 2270 Imager::Font::TT handle
02d1d628 2271 Imager::ImgRaw im
8d14daab
TC
2272 i_img_dim xb
2273 i_img_dim yb
02d1d628 2274 int channel
8d14daab 2275 double points
4f68b48f 2276 SV * str_sv
02d1d628 2277 int smooth
4f68b48f 2278 int utf8
9ab6338b 2279 int align
4f68b48f
TC
2280 PREINIT:
2281 char *str;
2282 STRLEN len;
2283 CODE:
e3b4d6c3 2284 str = SvPV(str_sv, len);
4f68b48f
TC
2285#ifdef SvUTF8
2286 if (SvUTF8(str_sv))
2287 utf8 = 1;
2288#endif
4f68b48f 2289 RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len,
9ab6338b 2290 smooth, utf8, align);
4f68b48f
TC
2291 OUTPUT:
2292 RETVAL
02d1d628
AMH
2293
2294
a659442a 2295void
7e3298ec 2296i_tt_bbox(handle,point,str_sv,utf8)
4b19f77a 2297 Imager::Font::TT handle
8d14daab 2298 double point
4f68b48f 2299 SV* str_sv
4f68b48f 2300 int utf8
02d1d628 2301 PREINIT:
8d14daab
TC
2302 i_img_dim cords[BOUNDING_BOX_COUNT];
2303 int rc;
4f68b48f
TC
2304 char * str;
2305 STRLEN len;
3799c4d1 2306 int i;
02d1d628 2307 PPCODE:
7e3298ec 2308 str = SvPV(str_sv, len);
4f68b48f
TC
2309#ifdef SvUTF8
2310 if (SvUTF8(ST(2)))
2311 utf8 = 1;
2312#endif
4f68b48f 2313 if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) {
3799c4d1
TC
2314 EXTEND(SP, rc);
2315 for (i = 0; i < rc; ++i) {
2316 PUSHs(sv_2mortal(newSViv(cords[i])));
2317 }
02d1d628
AMH
2318 }
2319
eeaa33fd
TC
2320void
2321i_tt_has_chars(handle, text_sv, utf8)
2322 Imager::Font::TT handle
2323 SV *text_sv
2324 int utf8
2325 PREINIT:
2326 char const *text;
2327 STRLEN len;
2328 char *work;
8d14daab
TC
2329 size_t count;
2330 size_t i;
eeaa33fd 2331 PPCODE:
7e3298ec
TC
2332 i_clear_error();
2333 text = SvPV(text_sv, len);
eeaa33fd
TC
2334#ifdef SvUTF8
2335 if (SvUTF8(text_sv))
2336 utf8 = 1;
2337#endif
eeaa33fd
TC
2338 work = mymalloc(len);
2339 count = i_tt_has_chars(handle, text, len, utf8, work);
2340 if (GIMME_V == G_ARRAY) {
2341 EXTEND(SP, count);
2342 for (i = 0; i < count; ++i) {
6e938c74 2343 PUSHs(boolSV(work[i]));
eeaa33fd
TC
2344 }
2345 }
2346 else {
2347 EXTEND(SP, 1);
2348 PUSHs(sv_2mortal(newSVpv(work, count)));
2349 }
2350 myfree(work);
02d1d628 2351
3799c4d1
TC
2352void
2353i_tt_dump_names(handle)
2354 Imager::Font::TT handle
02d1d628 2355
3799c4d1
TC
2356void
2357i_tt_face_name(handle)
2358 Imager::Font::TT handle
2359 PREINIT:
2360 char name[255];
8d14daab 2361 size_t len;
3799c4d1
TC
2362 PPCODE:
2363 len = i_tt_face_name(handle, name, sizeof(name));
2364 if (len) {
2365 EXTEND(SP, 1);
8d14daab 2366 PUSHs(sv_2mortal(newSVpv(name, len-1)));
3799c4d1 2367 }
02d1d628 2368
19fa4baf
AMH
2369void
2370i_tt_glyph_name(handle, text_sv, utf8 = 0)
3799c4d1
TC
2371 Imager::Font::TT handle
2372 SV *text_sv
2373 int utf8
2374 PREINIT:
2375 char const *text;
2376 STRLEN work_len;
718b8c97 2377 size_t len;
8d14daab 2378 size_t outsize;
3799c4d1 2379 char name[255];
7e3298ec 2380 SSize_t count = 0;
3799c4d1 2381 PPCODE:
7e3298ec
TC
2382 i_clear_error();
2383 text = SvPV(text_sv, work_len);
3799c4d1
TC
2384#ifdef SvUTF8
2385 if (SvUTF8(text_sv))
2386 utf8 = 1;
2387#endif
3799c4d1
TC
2388 len = work_len;
2389 while (len) {
17892255 2390 unsigned long ch;
3799c4d1
TC
2391 if (utf8) {
2392 ch = i_utf8_advance(&text, &len);
2393 if (ch == ~0UL) {
2394 i_push_error(0, "invalid UTF8 character");
7e3298ec 2395 XSRETURN_EMPTY;
3799c4d1
TC
2396 }
2397 }
2398 else {
2399 ch = *text++;
2400 --len;
2401 }
086b32d6 2402 EXTEND(SP, count+1);
af070d99 2403 if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
7e3298ec 2404 ST(count) = sv_2mortal(newSVpv(name, 0));
3799c4d1
TC
2405 }
2406 else {
7e3298ec
TC
2407 ST(count) = &PL_sv_undef;
2408 }
2409 ++count;
3799c4d1 2410 }
7e3298ec 2411 XSRETURN(count);
3799c4d1
TC
2412
2413#endif
02d1d628 2414
53a6bbd4 2415const char *
e10bf46e
AMH
2416i_test_format_probe(ig, length)
2417 Imager::IO ig
2418 int length
2419
02d1d628 2420Imager::ImgRaw
d87dc9a4 2421i_readpnm_wiol(ig, allow_incomplete)
02d1d628 2422 Imager::IO ig
d87dc9a4 2423 int allow_incomplete
02d1d628
AMH
2424
2425
2086be61
TC
2426void
2427i_readpnm_multi_wiol(ig, allow_incomplete)
2428 Imager::IO ig
2429 int allow_incomplete
2430 PREINIT:
2431 i_img **imgs;
2432 int count=0;
2433 int i;
2434 PPCODE:
2435 imgs = i_readpnm_multi_wiol(ig, &count, allow_incomplete);
2436 if (imgs) {
2437 EXTEND(SP, count);
2438 for (i = 0; i < count; ++i) {
2439 SV *sv = sv_newmortal();
2440 sv_setref_pv(sv, "Imager::ImgRaw", (void *)imgs[i]);
2441 PUSHs(sv);
2442 }
2443 myfree(imgs);
2444 }
2445
067d6bdc
AMH
2446undef_int
2447i_writeppm_wiol(im, ig)
2448 Imager::ImgRaw im
2449 Imager::IO ig
2450
2451
2086be61
TC
2452
2453
2454
02d1d628 2455Imager::ImgRaw
895dbd34
AMH
2456i_readraw_wiol(ig,x,y,datachannels,storechannels,intrl)
2457 Imager::IO ig
8d14daab
TC
2458 i_img_dim x
2459 i_img_dim y
02d1d628
AMH
2460 int datachannels
2461 int storechannels
2462 int intrl
2463
2464undef_int
895dbd34 2465i_writeraw_wiol(im,ig)
02d1d628 2466 Imager::ImgRaw im
895dbd34
AMH
2467 Imager::IO ig
2468
261f91c5
TC
2469undef_int
2470i_writebmp_wiol(im,ig)
2471 Imager::ImgRaw im
2472 Imager::IO ig
02d1d628 2473
705fd961 2474Imager::ImgRaw
d87dc9a4 2475i_readbmp_wiol(ig, allow_incomplete=0)
705fd961 2476 Imager::IO ig
d87dc9a4 2477 int allow_incomplete
705fd961 2478
1ec86afa
AMH
2479
2480undef_int
febba01f 2481i_writetga_wiol(im,ig, wierdpack, compress, idstring)
1ec86afa
AMH
2482 Imager::ImgRaw im
2483 Imager::IO ig
febba01f
AMH
2484 int wierdpack
2485 int compress
2486 char* idstring
2487 PREINIT:
febba01f
AMH
2488 int idlen;
2489 CODE:
2490 idlen = SvCUR(ST(4));
2491 RETVAL = i_writetga_wiol(im, ig, wierdpack, compress, idstring, idlen);
2492 OUTPUT:
2493 RETVAL
2494
1ec86afa
AMH
2495
2496Imager::ImgRaw
2497i_readtga_wiol(ig, length)
2498 Imager::IO ig
2499 int length
2500
2501
737a830c
AMH
2502
2503
02d1d628
AMH
2504Imager::ImgRaw
2505i_scaleaxis(im,Value,Axis)
2506 Imager::ImgRaw im
8d14daab 2507 double Value
02d1d628
AMH
2508 int Axis
2509
2510Imager::ImgRaw
2511i_scale_nn(im,scx,scy)
2512 Imager::ImgRaw im
8d14daab
TC
2513 double scx
2514 double scy
02d1d628 2515
658f724e
TC
2516Imager::ImgRaw
2517i_scale_mixing(im, width, height)
2518 Imager::ImgRaw im
8d14daab
TC
2519 i_img_dim width
2520 i_img_dim height
658f724e 2521
02d1d628
AMH
2522Imager::ImgRaw
2523i_haar(im)
2524 Imager::ImgRaw im
2525
2526int
2527i_count_colors(im,maxc)
2528 Imager::ImgRaw im
2529 int maxc
2530
fe622da1 2531void
a60905e4
TC
2532i_get_anonymous_color_histo(im, maxc = 0x40000000)
2533 Imager::ImgRaw im
2534 int maxc
4c99febf 2535 PREINIT:
fe622da1 2536 int i;
a60905e4 2537 unsigned int * col_usage = NULL;
4c99febf
TC
2538 int col_cnt;
2539 PPCODE:
2540 col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
fe622da1 2541 EXTEND(SP, col_cnt);
a60905e4
TC
2542 for (i = 0; i < col_cnt; i++) {
2543 PUSHs(sv_2mortal(newSViv( col_usage[i])));
fe622da1 2544 }
fe622da1
TC
2545 myfree(col_usage);
2546 XSRETURN(col_cnt);
2547
02d1d628 2548
fb9cb3f9 2549void
19e9591b 2550i_transform(im, opx, opy, parm)
02d1d628 2551 Imager::ImgRaw im
19e9591b
TC
2552 int *opx
2553 int *opy
2554 double *parm
02d1d628 2555 PREINIT:
19e9591b 2556 STRLEN size_opx, size_opy, size_parm;
fb9cb3f9
TC
2557 i_img *result;
2558 PPCODE:
19e9591b 2559 result=i_transform(im,opx,size_opx,opy,size_opy,parm,size_parm);
fb9cb3f9
TC
2560 if (result) {
2561 SV *result_sv = sv_newmortal();
2562 EXTEND(SP, 1);
2563 sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2564 PUSHs(result_sv);
2565 }
02d1d628 2566
fb9cb3f9 2567void
e5744e01
TC
2568i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs)
2569 SV *sv_width
2570 SV *sv_height
2571 SV *sv_ops
2572 AV *av_n_regs
2573 AV *av_c_regs
2574 AV *av_in_imgs
2575 int channels
02d1d628 2576 PREINIT:
8d14daab
TC
2577 i_img_dim width;
2578 i_img_dim height;
02d1d628 2579 struct rm_op *ops;
953209f8 2580 STRLEN ops_len;
02d1d628
AMH
2581 int ops_count;
2582 double *n_regs;
2583 int n_regs_count;
2584 i_color *c_regs;
2585 int c_regs_count;
2586 int in_imgs_count;
2587 i_img **in_imgs;
ea9e6c3f 2588 SV *sv1;
02d1d628
AMH
2589 IV tmp;
2590 int i;
fb9cb3f9
TC
2591 i_img *result;
2592 PPCODE:
e5744e01
TC
2593
2594 in_imgs_count = av_len(av_in_imgs)+1;
2595 for (i = 0; i < in_imgs_count; ++i) {
2596 sv1 = *av_fetch(av_in_imgs, i, 0);
2597 if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2598 croak("sv_in_img must contain only images");
02d1d628
AMH
2599 }
2600 }
b8c2033e 2601 if (in_imgs_count > 0) {
02d1d628
AMH
2602 in_imgs = mymalloc(in_imgs_count*sizeof(i_img*));
2603 for (i = 0; i < in_imgs_count; ++i) {
e5744e01 2604 sv1 = *av_fetch(av_in_imgs,i,0);
02d1d628
AMH
2605 if (!sv_derived_from(sv1, "Imager::ImgRaw")) {
2606 croak("Parameter 5 must contain only images");
2607 }
2608 tmp = SvIV((SV*)SvRV(sv1));
e375fbd8 2609 in_imgs[i] = INT2PTR(i_img*, tmp);
02d1d628
AMH
2610 }
2611 }
2612 else {
2613 /* no input images */
2614 in_imgs = NULL;
2615 }
2616 /* default the output size from the first input if possible */
e5744e01
TC
2617 if (SvOK(sv_width))
2618 width = SvIV(sv_width);
02d1d628
AMH
2619 else if (in_imgs_count)
2620 width = in_imgs[0]->xsize;
2621 else
2622 croak("No output image width supplied");
2623
e5744e01
TC
2624 if (SvOK(sv_height))
2625 height = SvIV(sv_height);
02d1d628
AMH
2626 else if (in_imgs_count)
2627 height = in_imgs[0]->ysize;
2628 else
2629 croak("No output image height supplied");
2630
e5744e01 2631 ops = (struct rm_op *)SvPV(sv_ops, ops_len);
02d1d628
AMH
2632 if (ops_len % sizeof(struct rm_op))
2633 croak("Imager: Parameter 3 must be a bitmap of regops\n");
2634 ops_count = ops_len / sizeof(struct rm_op);
e5744e01
TC
2635
2636 n_regs_count = av_len(av_n_regs)+1;
02d1d628
AMH
2637 n_regs = mymalloc(n_regs_count * sizeof(double));
2638 for (i = 0; i < n_regs_count; ++i) {
e5744e01 2639 sv1 = *av_fetch(av_n_regs,i,0);
02d1d628
AMH
2640 if (SvOK(sv1))
2641 n_regs[i] = SvNV(sv1);
2642 }
e5744e01 2643 c_regs_count = av_len(av_c_regs)+1;
02d1d628
AMH
2644 c_regs = mymalloc(c_regs_count * sizeof(i_color));
2645 /* I don't bother initializing the colou?r registers */
2646
fb9cb3f9 2647 result=i_transform2(width, height, channels, ops, ops_count,
02d1d628
AMH
2648 n_regs, n_regs_count,
2649 c_regs, c_regs_count, in_imgs, in_imgs_count);
2650 if (in_imgs)
2651 myfree(in_imgs);
2652 myfree(n_regs);
2653 myfree(c_regs);
fb9cb3f9
TC
2654 if (result) {
2655 SV *result_sv = sv_newmortal();
2656 EXTEND(SP, 1);
2657 sv_setref_pv(result_sv, "Imager::ImgRaw", (void*)result);
2658 PUSHs(result_sv);
2659 }
02d1d628
AMH
2660
2661
2662void
2663i_contrast(im,intensity)
2664 Imager::ImgRaw im
2665 float intensity
2666
2667void
2668i_hardinvert(im)
2669 Imager::ImgRaw im
2670
5558f899
TC
2671void
2672i_hardinvertall(im)
2673 Imager::ImgRaw im
2674
02d1d628
AMH
2675void
2676i_noise(im,amount,type)
2677 Imager::ImgRaw im
2678 float amount
2679 unsigned char type
2680
2681void
2682i_bumpmap(im,bump,channel,light_x,light_y,strength)
2683 Imager::ImgRaw im
2684 Imager::ImgRaw bump
2685 int channel
8d14daab
TC
2686 i_img_dim light_x
2687 i_img_dim light_y
2688 i_img_dim strength
02d1d628 2689
b2778574
AMH
2690
2691void
2692i_bumpmap_complex(im,bump,channel,tx,ty,Lx,Ly,Lz,cd,cs,n,Ia,Il,Is)
2693 Imager::ImgRaw im
2694 Imager::ImgRaw bump
2695 int channel
8d14daab
TC
2696 i_img_dim tx
2697 i_img_dim ty
2698 double Lx
2699 double Ly
2700 double Lz
b2778574
AMH
2701 float cd
2702 float cs
2703 float n
2704 Imager::Color Ia
2705 Imager::Color Il
2706 Imager::Color Is
2707
2708
2709
02d1d628
AMH
2710void
2711i_postlevels(im,levels)
2712 Imager::ImgRaw im
2713 int levels
2714
2715void
2716i_mosaic(im,size)
2717 Imager::ImgRaw im
8d14daab 2718 i_img_dim size
02d1d628
AMH
2719
2720void
2721i_watermark(im,wmark,tx,ty,pixdiff)
2722 Imager::ImgRaw im
2723 Imager::ImgRaw wmark
8d14daab
TC
2724 i_img_dim tx
2725 i_img_dim ty
02d1d628
AMH
2726 int pixdiff
2727
2728
2729void
2730i_autolevels(im,lsat,usat,skew)
2731 Imager::ImgRaw im
2732 float lsat
2733 float usat
2734 float skew
2735
ac00f58d
TC
2736void
2737i_autolevels_mono(im,lsat,usat)
2738 Imager::ImgRaw im
2739 float lsat
2740 float usat
2741
02d1d628
AMH
2742void
2743i_radnoise(im,xo,yo,rscale,ascale)
2744 Imager::ImgRaw im
2745 float xo
2746 float yo
2747 float rscale
2748 float ascale
2749
2750void
2751i_turbnoise(im, xo, yo, scale)
2752 Imager::ImgRaw im
2753 float xo
2754 float yo
2755 float scale
2756
2757
2758void
0aaa8b4d 2759i_gradgen(im, xo, yo, ac, dmeasure)
02d1d628 2760 Imager::ImgRaw im
0aaa8b4d
TC
2761 i_img_dim *xo
2762 i_img_dim *yo
2763 i_color *ac
2764 int dmeasure
02d1d628 2765 PREINIT:
0aaa8b4d
TC
2766 STRLEN size_xo;
2767 STRLEN size_yo;
2768 STRLEN size_ac;
02d1d628 2769 CODE:
0aaa8b4d
TC
2770 if (size_xo != size_yo || size_xo != size_ac)
2771 croak("i_gradgen: x, y and color arrays must be the same size");
2772 if (size_xo < 2)
2773 croak("Usage: i_gradgen array refs must have more than 1 entry each");
2774 i_gradgen(im, size_xo, xo, yo, ac, dmeasure);
a73aeb5f 2775
dff75dee
TC
2776Imager::ImgRaw
2777i_diff_image(im, im2, mindist=0)
2778 Imager::ImgRaw im
2779 Imager::ImgRaw im2
01b84320 2780 double mindist
02d1d628 2781
e310e5f9 2782undef_int
6607600c
TC
2783i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2784 Imager::ImgRaw im
2785 double xa
2786 double ya
2787 double xb
2788 double yb
2789 int type
2790 int repeat
2791 int combine
2792 int super_sample
2793 double ssample_param
2794 PREINIT:
6607600c 2795 AV *asegs;
6607600c
TC
2796 int count;
2797 i_fountain_seg *segs;
6607600c 2798 CODE:
6607600c
TC
2799 if (!SvROK(ST(10)) || ! SvTYPE(SvRV(ST(10))))
2800 croak("i_fountain: argument 11 must be an array ref");
2801
2802 asegs = (AV *)SvRV(ST(10));
b13a3ddb 2803 segs = load_fount_segs(aTHX_ asegs, &count);
e310e5f9
TC
2804 RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine,
2805 super_sample, ssample_param, count, segs);
6607600c 2806 myfree(segs);
e310e5f9
TC
2807 OUTPUT:
2808 RETVAL
02d1d628 2809
f1ac5027
TC
2810Imager::FillHandle
2811i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs)
2812 double xa
2813 double ya
2814 double xb
2815 double yb
2816 int type
2817 int repeat
2818 int combine
2819 int super_sample
2820 double ssample_param
2821 PREINIT:
2822 AV *asegs;
2823 int count;
2824 i_fountain_seg *segs;
2825 CODE:
2826 if (!SvROK(ST(9)) || ! SvTYPE(SvRV(ST(9))))
2827 croak("i_fountain: argument 11 must be an array ref");
2828
2829 asegs = (AV *)SvRV(ST(9));
b13a3ddb 2830 segs = load_fount_segs(aTHX_ asegs, &count);
f1ac5027
TC
2831 RETVAL = i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine,
2832 super_sample, ssample_param, count, segs);
2833 myfree(segs);
2834 OUTPUT:
2835 RETVAL
2836
52f2b10a
TC
2837Imager::FillHandle
2838i_new_fill_opacity(other_fill, alpha_mult)
2839 Imager::FillHandle other_fill
2840 double alpha_mult
2841
4f4f776a
TC
2842void
2843i_errors()
2844 PREINIT:
2845 i_errmsg *errors;
2846 int i;
4f4f776a 2847 AV *av;
4f4f776a
TC
2848 SV *sv;
2849 PPCODE:
2850 errors = i_errors();
2851 i = 0;
2852 while (errors[i].msg) {
2853 av = newAV();
2854 sv = newSVpv(errors[i].msg, strlen(errors[i].msg));
2855 if (!av_store(av, 0, sv)) {
2856 SvREFCNT_dec(sv);
2857 }
2858 sv = newSViv(errors[i].code);
2859 if (!av_store(av, 1, sv)) {
2860 SvREFCNT_dec(sv);
2861 }
2862 PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
2863 ++i;
2864 }
02d1d628 2865
2b405c9e
TC
2866void
2867i_clear_error()
2868
2869void
2870i_push_error(code, msg)
2871 int code
2872 const char *msg
2873
e310e5f9 2874undef_int
02d1d628
AMH
2875i_nearest_color(im, ...)
2876 Imager::ImgRaw im
2877 PREINIT:
2878 int num;
8d14daab
TC
2879 i_img_dim *xo;
2880 i_img_dim *yo;
02d1d628
AMH
2881 i_color *ival;
2882 int dmeasure;
2883 int i;
2884 SV *sv;
2885 AV *axx;
2886 AV *ayy;
2887 AV *ac;
2888 CODE:
2889 if (items != 5)
2890 croak("Usage: i_nearest_color(im, xo, yo, ival, dmeasure)");
2891 if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
2892 croak("i_nearest_color: Second argument must be an array ref");
2893 if (!SvROK(ST(2)) || ! SvTYPE(SvRV(ST(2))))
2894 croak("i_nearest_color: Third argument must be an array ref");
2895 if (!SvROK(ST(3)) || ! SvTYPE(SvRV(ST(3))))
2896 croak("i_nearest_color: Fourth argument must be an array ref");
2897 axx = (AV *)SvRV(ST(1));
2898 ayy = (AV *)SvRV(ST(2));
2899 ac = (AV *)SvRV(ST(3));
2900 dmeasure = (int)SvIV(ST(4));
2901
2902 num = av_len(axx) < av_len(ayy) ? av_len(axx) : av_len(ayy);
2903 num = num <= av_len(ac) ? num : av_len(ac);
2904 num++;
2905 if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
8d14daab
TC
2906 xo = mymalloc( sizeof(i_img_dim) * num );
2907 yo = mymalloc( sizeof(i_img_dim) * num );
02d1d628
AMH
2908 ival = mymalloc( sizeof(i_color) * num );
2909 for(i = 0; i<num; i++) {
8d14daab
TC
2910 xo[i] = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
2911 yo[i] = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
02d1d628
AMH
2912 sv = *av_fetch(ac, i, 0);
2913 if ( !sv_derived_from(sv, "Imager::Color") ) {
2914 free(axx); free(ayy); free(ac);
2915 croak("i_nearest_color: Element of fourth argument is not derived from Imager::Color");
2916 }
4c4c2ffd 2917 ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
02d1d628 2918 }
e310e5f9
TC
2919 RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure);
2920 OUTPUT:
2921 RETVAL
02d1d628
AMH
2922
2923void
2924malloc_state()
2925
02d1d628
AMH
2926void
2927DSO_open(filename)
2928 char* filename
2929 PREINIT:
2930 void *rc;
2931 char *evstr;
2932 PPCODE:
2933 rc=DSO_open(filename,&evstr);
2934 if (rc!=NULL) {
2935 if (evstr!=NULL) {
2936 EXTEND(SP,2);
e375fbd8 2937 PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
02d1d628
AMH
2938 PUSHs(sv_2mortal(newSVpvn(evstr, strlen(evstr))));
2939 } else {
2940 EXTEND(SP,1);
e375fbd8 2941 PUSHs(sv_2mortal(newSViv(PTR2IV(rc))));
02d1d628
AMH
2942 }
2943 }
2944
2945
2946undef_int
2947DSO_close(dso_handle)
2948 void* dso_handle
2949
2950void
2951DSO_funclist(dso_handle_v)
2952 void* dso_handle_v
2953 PREINIT:
2954 int i;
2955 DSO_handle *dso_handle;
d8e0c3ba 2956 func_ptr *functions;
02d1d628
AMH
2957 PPCODE:
2958 dso_handle=(DSO_handle*)dso_handle_v;
d8e0c3ba 2959 functions = DSO_funclist(dso_handle);
02d1d628 2960 i=0;
d8e0c3ba 2961 while( functions[i].name != NULL) {
02d1d628 2962 EXTEND(SP,1);
d8e0c3ba 2963 PUSHs(sv_2mortal(newSVpv(functions[i].name,0)));
02d1d628 2964 EXTEND(SP,1);
d8e0c3ba 2965 PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0)));
02d1d628
AMH
2966 }
2967
02d1d628
AMH
2968void
2969DSO_call(handle,func_index,hv)
2970 void* handle
2971 int func_index
75cebca8 2972 HV *hv
02d1d628 2973 PPCODE:
02d1d628
AMH
2974 DSO_call( (DSO_handle *)handle,func_index,hv);
2975
befd4be1 2976Imager::Color
f5991c03
TC
2977i_get_pixel(im, x, y)
2978 Imager::ImgRaw im
8d14daab
TC
2979 i_img_dim x
2980 i_img_dim y;
faa9b3e7 2981 CODE:
befd4be1
TC
2982 RETVAL = (i_color *)mymalloc(sizeof(i_color));
2983 if (i_gpix(im, x, y, RETVAL) != 0) {
2984 myfree(RETVAL);
2985 XSRETURN_UNDEF;
faa9b3e7 2986 }
a659442a
TC
2987 OUTPUT:
2988 RETVAL
faa9b3e7
TC
2989
2990
2991int
2992i_ppix(im, x, y, cl)
2993 Imager::ImgRaw im
8d14daab
TC
2994 i_img_dim x
2995 i_img_dim y
faa9b3e7
TC
2996 Imager::Color cl
2997
2998Imager::ImgRaw
2999i_img_pal_new(x, y, channels, maxpal)
8d14daab
TC
3000 i_img_dim x
3001 i_img_dim y
faa9b3e7
TC
3002 int channels
3003 int maxpal
3004
3005Imager::ImgRaw
3006i_img_to_pal(src, quant)
3007 Imager::ImgRaw src
3008 PREINIT:
3009 HV *hv;
3010 i_quantize quant;
3011 CODE:
3012 if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
3013 croak("i_img_to_pal: second argument must be a hash ref");
3014 hv = (HV *)SvRV(ST(1));
3015 memset(&quant, 0, sizeof(quant));
ec6d8908 3016 quant.version = 1;
faa9b3e7 3017 quant.mc_size = 256;
ec6d8908 3018 ip_handle_quant_opts(aTHX_ &quant, hv);
faa9b3e7
TC
3019 RETVAL = i_img_to_pal(src, &quant);
3020 if (RETVAL) {
ec6d8908 3021 ip_copy_colors_back(aTHX_ hv, &quant);
faa9b3e7 3022 }
ec6d8908 3023 ip_cleanup_quant_opts(aTHX_ &quant);
faa9b3e7
TC
3024 OUTPUT:
3025 RETVAL
3026
3027Imager::ImgRaw
3028i_img_to_rgb(src)
3029 Imager::ImgRaw src
3030
5e9a7fbd
TC
3031void
3032i_img_make_palette(HV *quant_hv, ...)
3033 PREINIT:
3034 size_t count = items - 1;
3035 i_quantize quant;
3036 i_img **imgs = NULL;
3037 ssize_t i;
3038 PPCODE:
3039 if (count <= 0)
3040 croak("Please supply at least one image (%d)", (int)count);
3041 imgs = mymalloc(sizeof(i_img *) * count);
3042 for (i = 0; i < count; ++i) {
3043 SV *img_sv = ST(i + 1);
3044 if (SvROK(img_sv) && sv_derived_from(img_sv, "Imager::ImgRaw")) {
3045 imgs[i] = INT2PTR(i_img *, SvIV((SV*)SvRV(img_sv)));
3046 }
3047 else {
3048 myfree(imgs);
ec2f6280 3049 croak("Image %d is not an image object", (int)i+1);
5e9a7fbd
TC
3050 }
3051 }
3052 memset(&quant, 0, sizeof(quant));
3053 quant.version = 1;
3054 quant.mc_size = 256;
3055 ip_handle_quant_opts(aTHX_ &quant, quant_hv);
3056 i_quant_makemap(&quant, imgs, count);
3057 EXTEND(SP, quant.mc_count);
3058 for (i = 0; i < quant.mc_count; ++i) {
3059 SV *sv_c = make_i_color_sv(aTHX_ quant.mc_colors + i);
3060 PUSHs(sv_c);
3061 }
3062 ip_cleanup_quant_opts(aTHX_ &quant);
3063
3064
faa9b3e7
TC
3065void
3066i_gpal(im, l, r, y)
3067 Imager::ImgRaw im
8d14daab
TC
3068 i_img_dim l
3069 i_img_dim r
3070 i_img_dim y
faa9b3e7
TC
3071 PREINIT:
3072 i_palidx *work;
3073 int count, i;
3074 PPCODE:
3075 if (l < r) {
3076 work = mymalloc((r-l) * sizeof(i_palidx));
3077 count = i_gpal(im, l, r, y, work);
3078 if (GIMME_V == G_ARRAY) {
3079 EXTEND(SP, count);
3080 for (i = 0; i < count; ++i) {
3081 PUSHs(sv_2mortal(newSViv(work[i])));
3082 }
3083 }
3084 else {
3085 EXTEND(SP, 1);
26fd367b 3086 PUSHs(sv_2mortal(newSVpv((char *)work, count * sizeof(i_palidx))));
faa9b3e7
TC
3087 }
3088 myfree(work);
3089 }
3090 else {
3091 if (GIMME_V != G_ARRAY) {
3092 EXTEND(SP, 1);
3093 PUSHs(&PL_sv_undef);
3094 }
3095 }
3096
3097int
3098i_ppal(im, l, y, ...)
3099 Imager::ImgRaw im
8d14daab
TC
3100 i_img_dim l
3101 i_img_dim y
faa9b3e7
TC
3102 PREINIT:
3103 i_palidx *work;
ebe9b189 3104 i_img_dim i;
faa9b3e7
TC
3105 CODE:
3106 if (items > 3) {
ebe9b189 3107 work = malloc_temp(aTHX_ sizeof(i_palidx) * (items-3));
faa9b3e7
TC
3108 for (i=0; i < items-3; ++i) {
3109 work[i] = SvIV(ST(i+3));
3110 }
4cda4e76 3111 validate_i_ppal(im, work, items - 3);
faa9b3e7 3112 RETVAL = i_ppal(im, l, l+items-3, y, work);
faa9b3e7
TC
3113 }
3114 else {
3115 RETVAL = 0;
3116 }
3117 OUTPUT:
3118 RETVAL
3119
4cda4e76
TC
3120int
3121i_ppal_p(im, l, y, data)
3122 Imager::ImgRaw im
8d14daab
TC
3123 i_img_dim l
3124 i_img_dim y
4cda4e76
TC
3125 SV *data
3126 PREINIT:
3127 i_palidx const *work;
4cda4e76 3128 STRLEN len;
4cda4e76
TC
3129 CODE:
3130 work = (i_palidx const *)SvPV(data, len);
3131 len /= sizeof(i_palidx);
3132 if (len > 0) {
3133 validate_i_ppal(im, work, len);
3134 RETVAL = i_ppal(im, l, l+len, y, work);
3135 }
3136 else {
3137 RETVAL = 0;
3138 }
3139 OUTPUT:
3140 RETVAL
3141
42505e61 3142SysRet
faa9b3e7
TC
3143i_addcolors(im, ...)
3144 Imager::ImgRaw im
3145 PREINIT:
faa9b3e7
TC
3146 i_color *colors;
3147 int i;
3148 CODE:
3149 if (items < 2)
3150 croak("i_addcolors: no colors to add");
3151 colors = mymalloc((items-1) * sizeof(i_color));
3152 for (i=0; i < items-1; ++i) {
3153 if (sv_isobject(ST(i+1))
3154 && sv_derived_from(ST(i+1), "Imager::Color")) {
3155 IV tmp = SvIV((SV *)SvRV(ST(i+1)));
4c4c2ffd 3156 colors[i] = *INT2PTR(i_color *, tmp);
faa9b3e7
TC
3157 }
3158 else {
3159 myfree(colors);
ca4d914e 3160 croak("i_addcolor: pixels must be Imager::Color objects");
faa9b3e7
TC
3161 }
3162 }
42505e61 3163 RETVAL = i_addcolors(im, colors, items-1);
a659442a
TC
3164 OUTPUT:
3165 RETVAL
faa9b3e7 3166
1501d9b3 3167undef_int
faa9b3e7
TC
3168i_setcolors(im, index, ...)
3169 Imager::ImgRaw im
3170 int index
3171 PREINIT:
3172 i_color *colors;
3173 int i;
3174 CODE:
3175 if (items < 3)
3176 croak("i_setcolors: no colors to add");
3177 colors = mymalloc((items-2) * sizeof(i_color));
3178 for (i=0; i < items-2; ++i) {
3179 if (sv_isobject(ST(i+2))
3180 && sv_derived_from(ST(i+2), "Imager::Color")) {
3181 IV tmp = SvIV((SV *)SvRV(ST(i+2)));
4c4c2ffd 3182 colors[i] = *INT2PTR(i_color *, tmp);
faa9b3e7
TC
3183 }
3184 else {
3185 myfree(colors);
3186 croak("i_setcolors: pixels must be Imager::Color objects");
3187 }
3188 }
3189 RETVAL = i_setcolors(im, index, colors, items-2);
3190 myfree(colors);
1501d9b3
TC
3191 OUTPUT:
3192 RETVAL
faa9b3e7
TC
3193
3194void
1592522f 3195i_getcolors(im, index, count=1)
faa9b3e7
TC
3196 Imager::ImgRaw im
3197 int index
1592522f 3198 int count
faa9b3e7
TC
3199 PREINIT:
3200 i_color *colors;
faa9b3e7
TC
3201 int i;
3202 PPCODE:
faa9b3e7
TC
3203 if (count < 1)
3204 croak("i_getcolors: count must be positive");
1592522f 3205 colors = malloc_temp(aTHX_ sizeof(i_color) * count);
faa9b3e7 3206 if (i_getcolors(im, index, colors, count)) {
1592522f 3207 EXTEND(SP, count);
faa9b3e7 3208 for (i = 0; i < count; ++i) {
5e9a7fbd 3209 SV *sv = make_i_color_sv(aTHX_ colors+i);
faa9b3e7
TC
3210 PUSHs(sv);
3211 }
3212 }
faa9b3e7 3213
a659442a 3214undef_neg_int
faa9b3e7
TC
3215i_colorcount(im)
3216 Imager::ImgRaw im
faa9b3e7 3217
a659442a 3218undef_neg_int
faa9b3e7
TC
3219i_maxcolors(im)
3220 Imager::ImgRaw im
faa9b3e7 3221
0862f397 3222i_palidx
faa9b3e7
TC
3223i_findcolor(im, color)
3224 Imager::ImgRaw im
3225 Imager::Color color
faa9b3e7 3226 CODE:
0862f397
TC
3227 if (!i_findcolor(im, color, &RETVAL)) {
3228 XSRETURN_UNDEF;
faa9b3e7 3229 }
a659442a
TC
3230 OUTPUT:
3231 RETVAL
faa9b3e7
TC
3232
3233int
3234i_img_bits(im)
3235 Imager::ImgRaw im
3236
3237int
3238i_img_type(im)
3239 Imager::ImgRaw im
3240
3241int
3242i_img_virtual(im)
3243 Imager::ImgRaw im
3244
3245void
6a9807e8 3246i_gsamp(im, l, r, y, channels)
faa9b3e7 3247 Imager::ImgRaw im
8d14daab
TC
3248 i_img_dim l
3249 i_img_dim r
3250 i_img_dim y
6a9807e8 3251 i_channel_list channels
faa9b3e7 3252 PREINIT:
faa9b3e7 3253 i_sample_t *data;
8d14daab 3254 i_img_dim count, i;
faa9b3e7 3255 PPCODE:
faa9b3e7 3256 if (l < r) {
f37708ce 3257 data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
6a9807e8 3258 count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
faa9b3e7
TC
3259 if (GIMME_V == G_ARRAY) {
3260 EXTEND(SP, count);
3261 for (i = 0; i < count; ++i)
3262 PUSHs(sv_2mortal(newSViv(data[i])));
3263 }
3264 else {
3265 EXTEND(SP, 1);
26fd367b 3266 PUSHs(sv_2mortal(newSVpv((char *)data, count * sizeof(i_sample_t))));
faa9b3e7 3267 }
a73aeb5f 3268 myfree(data);
faa9b3e7
TC
3269 }
3270 else {
3271 if (GIMME_V != G_ARRAY) {
f37708ce 3272 XSRETURN_UNDEF;
faa9b3e7
TC
3273 }
3274 }
3275
bd8052a6 3276undef_neg_int
6a9807e8 3277i_gsamp_bits(im, l, r, y, bits, target, offset, channels)
bd8052a6 3278 Imager::ImgRaw im
8d14daab
TC
3279 i_img_dim l
3280 i_img_dim r
3281 i_img_dim y
bd8052a6
TC
3282 int bits
3283 AV *target
8d14daab 3284 STRLEN offset
6a9807e8 3285 i_channel_list channels
bd8052a6 3286 PREINIT:
bd8052a6 3287 unsigned *data;
8d14daab 3288 i_img_dim count, i;
bd8052a6
TC
3289 CODE:
3290 i_clear_error();
3291 if (items < 8)
3292 croak("No channel numbers supplied to g_samp()");
3293 if (l < r) {
6a9807e8
TC
3294 data = mymalloc(sizeof(unsigned) * (r-l) * channels.count);
3295 count = i_gsamp_bits(im, l, r, y, data, channels.channels, channels.count, bits);
bd8052a6
TC
3296 for (i = 0; i < count; ++i) {
3297 av_store(target, i+offset, newSVuv(data[i]));
3298 }
3299 myfree(data);
3300 RETVAL = count;
3301 }
3302 else {
3303 RETVAL = 0;
3304 }
3305 OUTPUT:
3306 RETVAL
3307
3308undef_neg_int
6a9807e8 3309i_psamp_bits(im, l, y, bits, channels, data_av, data_offset = 0, pixel_count = -1)
bd8052a6 3310 Imager::ImgRaw im
8d14daab
TC
3311 i_img_dim l
3312 i_img_dim y
bd8052a6 3313 int bits
6a9807e8 3314 i_channel_list channels
bd8052a6 3315 AV *data_av
848b7f32
TC
3316 i_img_dim data_offset
3317 i_img_dim pixel_count
bd8052a6 3318 PREINIT:
8d14daab
TC
3319 STRLEN data_count;
3320 size_t data_used;
bd8052a6 3321 unsigned *data;
8d14daab 3322 ptrdiff_t i;
bd8052a6
TC
3323 CODE:
3324 i_clear_error();
bd8052a6
TC
3325
3326 data_count = av_len(data_av) + 1;
3327 if (data_offset < 0) {
848b7f32 3328 croak("data_offset must be non-negative");
bd8052a6
TC
3329 }
3330 if (data_offset > data_count) {
3331 croak("data_offset greater than number of samples supplied");
3332 }
3333 if (pixel_count == -1 ||
6a9807e8
TC
3334 data_offset + pixel_count * channels.count > data_count) {
3335 pixel_count = (data_count - data_offset) / channels.count;
bd8052a6
TC
3336 }
3337
6a9807e8 3338 data_used = pixel_count * channels.count;
bd8052a6
TC
3339 data = mymalloc(sizeof(unsigned) * data_count);
3340 for (i = 0; i < data_used; ++i)
3341 data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0));
3342
6a9807e8
TC
3343 RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels.channels,
3344 channels.count, bits);
bd8052a6
TC
3345
3346 if (data)
3347 myfree(data);
bd8052a6
TC
3348 OUTPUT:
3349 RETVAL
a73aeb5f 3350
48b9a7bf 3351undef_neg_int
848b7f32 3352i_psamp(im, x, y, channels, data, offset = 0, width = -1)
48b9a7bf
TC
3353 Imager::ImgRaw im
3354 i_img_dim x
3355 i_img_dim y
3356 i_channel_list channels
3357 i_sample_list data
848b7f32
TC
3358 i_img_dim offset
3359 i_img_dim width
48b9a7bf
TC
3360 PREINIT:
3361 i_img_dim r;
3362 CODE:
48b9a7bf 3363 i_clear_error();
848b7f32
TC
3364 if (offset < 0) {
3365 i_push_error(0, "offset must be non-negative");
3366 XSRETURN_UNDEF;
3367 }
3368 if (offset > 0) {
3369 if (offset > data.count) {
3370 i_push_error(0, "offset greater than number of samples supplied");
3371 XSRETURN_UNDEF;
3372 }
3373 data.samples += offset;
3374 data.count -= offset;
3375 }
3376 if (width == -1 ||
3377 width * channels.count > data.count) {
3378 width = data.count / channels.count;
3379 }
3380 r = x + width;
48b9a7bf
TC
3381 RETVAL = i_psamp(im, x, r, y, data.samples, channels.channels, channels.count);
3382 OUTPUT:
3383 RETVAL
3384
3385undef_neg_int
848b7f32 3386i_psampf(im, x, y, channels, data, offset = 0, width = -1)
48b9a7bf
TC
3387 Imager::ImgRaw im
3388 i_img_dim x
3389 i_img_dim y
3390 i_channel_list channels
3391 i_fsample_list data
848b7f32
TC
3392 i_img_dim offset
3393 i_img_dim width
48b9a7bf
TC
3394 PREINIT:
3395 i_img_dim r;
3396 CODE:
48b9a7bf 3397 i_clear_error();
848b7f32
TC
3398 if (offset < 0) {
3399 i_push_error(0, "offset must be non-negative");
3400 XSRETURN_UNDEF;
3401 }
3402 if (offset > 0) {
3403 if (offset > data.count) {
3404 i_push_error(0, "offset greater than number of samples supplied");
3405 XSRETURN_UNDEF;
3406 }
3407 data.samples += offset;
3408 data.count -= offset;
3409 }
3410 if (width == -1 ||
3411 width * channels.count > data.count) {
3412 width = data.count / channels.count;
3413 }
3414 r = x + width;
48b9a7bf
TC
3415 RETVAL = i_psampf(im, x, r, y, data.samples, channels.channels, channels.count);
3416 OUTPUT:
3417 RETVAL
3418
faa9b3e7
TC
3419Imager::ImgRaw
3420i_img_masked_new(targ, mask, x, y, w, h)
3421 Imager::ImgRaw targ
8d14daab
TC
3422 i_img_dim x
3423 i_img_dim y
3424 i_img_dim w
3425 i_img_dim h
faa9b3e7
TC
3426 PREINIT:
3427 i_img *mask;
3428 CODE:
3429 if (SvOK(ST(1))) {
3430 if (!sv_isobject(ST(1))
3431 || !sv_derived_from(ST(1), "Imager::ImgRaw")) {
3432 croak("i_img_masked_new: parameter 2 must undef or an image");
3433 }
4c4c2ffd 3434 mask = INT2PTR(i_img *, SvIV((SV *)SvRV(ST(1))));
faa9b3e7
TC
3435 }
3436 else
3437 mask = NULL;
3438 RETVAL = i_img_masked_new(targ, mask, x, y, w, h);
3439 OUTPUT:
3440 RETVAL
3441
3442int
3443i_plin(im, l, y, ...)
3444 Imager::ImgRaw im
8d14daab
TC
3445 i_img_dim l
3446 i_img_dim y
faa9b3e7
TC
3447 PREINIT:
3448 i_color *work;
8d14daab 3449 STRLEN i;
ca4d914e 3450 STRLEN len;
8d14daab 3451 size_t count;
faa9b3e7
TC
3452 CODE:
3453 if (items > 3) {
ca4d914e
TC
3454 if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3455 /* supplied as a byte string */
3456 work = (i_color *)SvPV(ST(3), len);
3457 count = len / sizeof(i_color);
3458 if (count * sizeof(i_color) != len) {
3459 croak("i_plin: length of scalar argument must be multiple of sizeof i_color");
faa9b3e7 3460 }
ca4d914e
TC
3461 RETVAL = i_plin(im, l, l+count, y, work);
3462 }
3463 else {
3464 work = mymalloc(sizeof(i_color) * (items-3));
3465 for (i=0; i < items-3; ++i) {
3466 if (sv_isobject(ST(i+3))
3467 && sv_derived_from(ST(i+3), "Imager::Color")) {
3468 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3469 work[i] = *INT2PTR(i_color *, tmp);
3470 }
3471 else {
3472 myfree(work);
3473 croak("i_plin: pixels must be Imager::Color objects");
3474 }
faa9b3e7 3475 }
ca4d914e
TC
3476 RETVAL = i_plin(im, l, l+items-3, y, work);
3477 myfree(work);
faa9b3e7 3478 }
faa9b3e7
TC
3479 }
3480 else {
3481 RETVAL = 0;
3482 }
3483 OUTPUT:
3484 RETVAL
3485
3486int
3487i_ppixf(im, x, y, cl)
3488 Imager::ImgRaw im
8d14daab
TC
3489 i_img_dim x
3490 i_img_dim y
faa9b3e7
TC
3491 Imager::Color::Float cl
3492
3493void
6a9807e8 3494i_gsampf(im, l, r, y, channels)
faa9b3e7 3495 Imager::ImgRaw im
8d14daab
TC
3496 i_img_dim l
3497 i_img_dim r
3498 i_img_dim y
6a9807e8 3499 i_channel_list channels
faa9b3e7 3500 PREINIT:
faa9b3e7 3501 i_fsample_t *data;
8d14daab 3502 i_img_dim count, i;
faa9b3e7 3503 PPCODE:
faa9b3e7 3504 if (l < r) {
6a9807e8
TC
3505 data = mymalloc(sizeof(i_fsample_t) * (r-l) * channels.count);
3506 count = i_gsampf(im, l, r, y, data, channels.channels, channels.count);
faa9b3e7
TC
3507 if (GIMME_V == G_ARRAY) {
3508 EXTEND(SP, count);
3509 for (i = 0; i < count; ++i)
3510 PUSHs(sv_2mortal(newSVnv(data[i])));
3511 }
3512 else {
3513 EXTEND(SP, 1);
3514 PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t))));
3515 }
3631271b 3516 myfree(data);
faa9b3e7
TC
3517 }
3518 else {
3519 if (GIMME_V != G_ARRAY) {
5736f588 3520 XSRETURN_UNDEF;
faa9b3e7
TC
3521 }
3522 }
3523
3524int
3525i_plinf(im, l, y, ...)
3526 Imager::ImgRaw im
8d14daab
TC
3527 i_img_dim l
3528 i_img_dim y
faa9b3e7
TC
3529 PREINIT:
3530 i_fcolor *work;
8d14daab 3531 i_img_dim i;
ca4d914e 3532 STRLEN len;
8d14daab 3533 size_t count;
faa9b3e7
TC
3534 CODE:
3535 if (items > 3) {
ca4d914e
TC
3536 if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) {
3537 /* supplied as a byte string */
3538 work = (i_fcolor *)SvPV(ST(3), len);
3539 count = len / sizeof(i_fcolor);
3540 if (count * sizeof(i_fcolor) != len) {
3541 croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor");
faa9b3e7 3542 }
ca4d914e
TC
3543 RETVAL = i_plinf(im, l, l+count, y, work);
3544 }
3545 else {
3546 work = mymalloc(sizeof(i_fcolor) * (items-3));
3547 for (i=0; i < items-3; ++i) {
3548 if (sv_isobject(ST(i+3))
3549 && sv_derived_from(ST(i+3), "Imager::Color::Float")) {
3550 IV tmp = SvIV((SV *)SvRV(ST(i+3)));
3551 work[i] = *INT2PTR(i_fcolor *, tmp);
3552 }
3553 else {
3554 myfree(work);
3555 croak("i_plinf: pixels must be Imager::Color::Float objects");
3556 }
faa9b3e7 3557 }
ca4d914e
TC
3558 /**(char *)0 = 1;*/
3559 RETVAL = i_plinf(im, l, l+items-3, y, work);
3560 myfree(work);
faa9b3e7 3561 }
faa9b3e7
TC
3562 }
3563 else {
3564 RETVAL = 0;
3565 }
3566 OUTPUT:
3567 RETVAL
3568
73d80423 3569Imager::Color::Float
faa9b3e7
TC
3570i_gpixf(im, x, y)
3571 Imager::ImgRaw im
8d14daab
TC
3572 i_img_dim x
3573 i_img_dim y;
faa9b3e7 3574 CODE:
73d80423
TC
3575 RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
3576 if (i_gpixf(im, x, y, RETVAL) != 0) {
3577 myfree(RETVAL);
3578 XSRETURN_UNDEF;
faa9b3e7 3579 }
a659442a
TC
3580 OUTPUT:
3581 RETVAL
3582
faa9b3e7
TC
3583void
3584i_glin(im, l, r, y)
3585 Imager::ImgRaw im
8d14daab
TC
3586 i_img_dim l
3587 i_img_dim r
3588 i_img_dim y
faa9b3e7
TC
3589 PREINIT:
3590 i_color *vals;
8d14daab 3591 i_img_dim count, i;
faa9b3e7
TC
3592 PPCODE:
3593 if (l < r) {
3594 vals = mymalloc((r-l) * sizeof(i_color));
b3aa972f 3595 memset(vals, 0, (r-l) * sizeof(i_color));
faa9b3e7 3596 count = i_glin(im, l, r, y, vals);
ca4d914e
TC
3597 if (GIMME_V == G_ARRAY) {
3598 EXTEND(SP, count);
3599 for (i = 0; i < count; ++i) {
5e9a7fbd 3600 SV *sv = make_i_color_sv(aTHX_ vals+i);
ca4d914e
TC
3601 PUSHs(sv);
3602 }
3603 }
3604 else if (count) {
3605 EXTEND(SP, 1);
3606 PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color))));
faa9b3e7
TC
3607 }
3608 myfree(vals);
3609 }
3610
3611void
3612i_glinf(im, l, r, y)
3613 Imager::ImgRaw im
8d14daab
TC
3614 i_img_dim l
3615 i_img_dim r
3616 i_img_dim y
faa9b3e7
TC
3617 PREINIT:
3618 i_fcolor *vals;
8d14daab 3619 i_img_dim count, i;
919e0000 3620 i_fcolor zero;
faa9b3e7 3621 PPCODE:
919e0000
TC
3622 for (i = 0; i < MAXCHANNELS; ++i)
3623 zero.channel[i] = 0;
faa9b3e7
TC
3624 if (l < r) {
3625 vals = mymalloc((r-l) * sizeof(i_fcolor));
b3aa972f
TC
3626 for (i = 0; i < r-l; ++i)
3627 vals[i] = zero;
faa9b3e7 3628 count = i_glinf(im, l, r, y, vals);
ca4d914e
TC
3629 if (GIMME_V == G_ARRAY) {
3630 EXTEND(SP, count);
3631 for (i = 0; i < count; ++i) {
3632 SV *sv;
3633 i_fcolor *col = mymalloc(sizeof(i_fcolor));
3634 *col = vals[i];
3635 sv = sv_newmortal();
3636 sv_setref_pv(sv, "Imager::Color::Float", (void *)col);
3637 PUSHs(sv);
3638 }
3639 }
3640 else if (count) {
3641 EXTEND(SP, 1);
3642 PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor))));
faa9b3e7
TC
3643 }
3644 myfree(vals);
3645 }
3646
bdd4c63b
TC
3647Imager::ImgRaw
3648i_img_8_new(x, y, ch)
3649 i_img_dim x
3650 i_img_dim y
3651 int ch
3652
faa9b3e7
TC
3653Imager::ImgRaw
3654i_img_16_new(x, y, ch)
8d14daab
TC
3655 i_img_dim x
3656 i_img_dim y
faa9b3e7
TC
3657 int ch
3658
167660cd
TC
3659Imager::ImgRaw
3660i_img_to_rgb16(im)
3661 Imager::ImgRaw im
3662
365ea842
TC
3663Imager::ImgRaw
3664i_img_double_new(x, y, ch)
8d14daab
TC
3665 i_img_dim x
3666 i_img_dim y
365ea842
TC
3667 int ch
3668
bfe6ba3f
TC
3669Imager::ImgRaw
3670i_img_to_drgb(im)
3671 Imager::ImgRaw im
3672
faa9b3e7 3673undef_int
b9e2571f 3674i_tags_addn(im, name_sv, code, idata)
faa9b3e7 3675 Imager::ImgRaw im
b9e2571f 3676 SV *name_sv
faa9b3e7
TC
3677 int code
3678 int idata
3679 PREINIT:
3680 char *name;
3681 STRLEN len;
3682 CODE:
b9e2571f
TC
3683 SvGETMAGIC(name_sv);
3684 if (SvOK(name_sv))
3685 name = SvPV_nomg(name_sv, len);
faa9b3e7
TC
3686 else
3687 name = NULL;
3688 RETVAL = i_tags_addn(&im->tags, name, code, idata);
3689 OUTPUT:
3690 RETVAL
3691
3692undef_int
a4da28d7 3693i_tags_add(im, name_sv, code, data_sv, idata)
faa9b3e7 3694 Imager::ImgRaw im
a4da28d7 3695 SV *name_sv
faa9b3e7 3696 int code
a4da28d7 3697 SV *data_sv
faa9b3e7
TC
3698 int idata
3699 PREINIT:
3700 char *name;
3701 char *data;
3702 STRLEN len;
3703 CODE:
a4da28d7
TC
3704 SvGETMAGIC(name_sv);
3705 if (SvOK(name_sv))
3706 name = SvPV_nomg(name_sv, len);
faa9b3e7
TC
3707 else
3708 name = NULL;
a4da28d7
TC
3709 SvGETMAGIC(data_sv);
3710 if (SvOK(data_sv))
3711 data = SvPV(data_sv, len);
faa9b3e7
TC
3712 else {
3713 data = NULL;
3714 len = 0;
3715 }
3716 RETVAL = i_tags_add(&im->tags, name, code, data, len, idata);
3717 OUTPUT:
3718 RETVAL
3719
f4aca831 3720SysRet
faa9b3e7
TC
3721i_tags_find(im, name, start)
3722 Imager::ImgRaw im
3723 char *name
3724 int start
3725 PREINIT:
3726 int entry;
3727 CODE:
3728 if (i_tags_find(&im->tags, name, start, &entry)) {
f4aca831 3729 RETVAL = entry;
faa9b3e7 3730 } else {
f4aca831 3731 XSRETURN_UNDEF;
faa9b3e7 3732 }
a659442a
TC
3733 OUTPUT:
3734 RETVAL
faa9b3e7 3735
f4aca831 3736SysRet
faa9b3e7
TC
3737i_tags_findn(im, code, start)
3738 Imager::ImgRaw im
3739 int code
3740 int start
3741 PREINIT:
3742 int entry;
3743 CODE:
3744 if (i_tags_findn(&im->tags, code, start, &entry)) {
f4aca831 3745 RETVAL = entry;
faa9b3e7 3746 }
a659442a 3747 else {
f4aca831 3748 XSRETURN_UNDEF;
a659442a
TC
3749 }
3750 OUTPUT:
3751 RETVAL
faa9b3e7
TC
3752
3753int
3754i_tags_delete(im, entry)
3755 Imager::ImgRaw im
3756 int entry
3757 CODE:
3758 RETVAL = i_tags_delete(&im->tags, entry);
3759 OUTPUT:
3760 RETVAL
3761
3762int
3763i_tags_delbyname(im, name)
3764 Imager::ImgRaw im
3765 char * name
3766 CODE:
3767 RETVAL = i_tags_delbyname(&im->tags, name);
3768 OUTPUT:
3769 RETVAL
3770
3771int
3772i_tags_delbycode(im, code)
3773 Imager::ImgRaw im
3774 int code
3775 CODE:
3776 RETVAL = i_tags_delbycode(&im->tags, code);
3777 OUTPUT:
3778 RETVAL
3779
3780void
3781i_tags_get(im, index)
3782 Imager::ImgRaw im
3783 int index
3784 PPCODE:
3785 if (index >= 0 && index < im->tags.count) {
3786 i_img_tag *entry = im->tags.tags + index;
3787 EXTEND(SP, 5);
3788
3789 if (entry->name) {
3790 PUSHs(sv_2mortal(newSVpv(entry->name, 0)));
3791 }
3792 else {
3793 PUSHs(sv_2mortal(newSViv(entry->code)));
3794 }
3795 if (entry->data) {
3796 PUSHs(sv_2mortal(newSVpvn(entry->data, entry->size)));
3797 }
3798 else {
3799 PUSHs(sv_2mortal(newSViv(entry->idata)));
3800 }
3801 }
3802
241defe8
TC
3803void
3804i_tags_get_string(im, what_sv)
3805 Imager::ImgRaw im
3806 SV *what_sv
3807 PREINIT:
3808 char const *name = NULL;
3809 int code;
3810 char buffer[200];
241defe8
TC
3811 PPCODE:
3812 if (SvIOK(what_sv)) {
3813 code = SvIV(what_sv);
3814 name = NULL;
3815 }
3816 else {
3817 name = SvPV_nolen(what_sv);
3818 code = 0;
3819 }
3820 if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) {
3821 EXTEND(SP, 1);
3822 PUSHs(sv_2mortal(newSVpv(buffer, 0)));
3823 }
3824
faa9b3e7
TC
3825int
3826i_tags_count(im)
3827 Imager::ImgRaw im
3828 CODE:
3829 RETVAL = im->tags.count;
3830 OUTPUT:
3831 RETVAL
3832
faa9b3e7 3833
faa9b3e7 3834
f1ac5027
TC
3835MODULE = Imager PACKAGE = Imager::FillHandle PREFIX=IFILL_
3836
3837void
3838IFILL_DESTROY(fill)
3839 Imager::FillHandle fill
3840
ffddd407
TC
3841int
3842IFILL_CLONE_SKIP(...)
3843 CODE:
8d14daab 3844 (void)items; /* avoid unused warning for XS variable */
ffddd407
TC
3845 RETVAL = 1;
3846 OUTPUT:
3847 RETVAL
3848
f1ac5027
TC
3849MODULE = Imager PACKAGE = Imager
3850
3851Imager::FillHandle
3852i_new_fill_solid(cl, combine)
3853 Imager::Color cl
3854 int combine
3855
3856Imager::FillHandle
3857i_new_fill_solidf(cl, combine)
3858 Imager::Color::Float cl
3859 int combine
3860
3861Imager::FillHandle
a309fbc6 3862i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
f1ac5027
TC
3863 Imager::Color fg
3864 Imager::Color bg
3865 int combine
3866 int hatch
a309fbc6 3867 SV *cust_hatch_sv
8d14daab
TC
3868 i_img_dim dx
3869 i_img_dim dy
f1ac5027
TC
3870 PREINIT:
3871 unsigned char *cust_hatch;
3872 STRLEN len;
3873 CODE:
a309fbc6
TC
3874 SvGETMAGIC(cust_hatch_sv);
3875 if (SvOK(cust_hatch_sv)) {
3876 cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
f1ac5027
TC
3877 }
3878 else
3879 cust_hatch = NULL;
3880 RETVAL = i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy);
3881 OUTPUT:
3882 RETVAL
3883
efdc2568 3884Imager::FillHandle
a309fbc6 3885i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
efdc2568
TC
3886 Imager::Color::Float fg
3887 Imager::Color::Float bg
3888 int combine
3889 int hatch
a309fbc6 3890 SV *cust_hatch_sv
8d14daab
TC
3891 i_img_dim dx
3892 i_img_dim dy
efdc2568
TC
3893 PREINIT:
3894 unsigned char *cust_hatch;
3895 STRLEN len;
3896 CODE:
a309fbc6
TC
3897 SvGETMAGIC(cust_hatch_sv);
3898 if (SvOK(cust_hatch_sv)) {
3899 cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
efdc2568
TC
3900 }
3901 else
3902 cust_hatch = NULL;
3903 RETVAL = i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy);
3904 OUTPUT:
3905 RETVAL
3906
f576ce7e 3907Imager::FillHandle
c0f38779 3908i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
f576ce7e 3909 Imager::ImgRaw src
c0f38779 3910 SV *matrix_sv
8d14daab
TC
3911 i_img_dim xoff
3912 i_img_dim yoff
f576ce7e
TC
3913 int combine
3914 PREINIT:
3915 double matrix[9];
3916 double *matrixp;
3917 AV *av;
3918 IV len;
3919 SV *sv1;
3920 int i;
3921 CODE:
c0f38779
TC
3922 SvGETMAGIC(matrix_sv);
3923 if (!SvOK(matrix_sv)) {
f576ce7e
TC
3924 matrixp = NULL;
3925 }
3926 else {
c0f38779
TC
3927 if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
3928 croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
3929 av=(AV*)SvRV(matrix_sv);
f576ce7e
TC
3930 len=av_len(av)+1;
3931 if (len > 9)
3932 len = 9;
3933 for (i = 0; i < len; ++i) {
3934 sv1=(*(av_fetch(av,i,0)));
3935 matrix[i] = SvNV(sv1);
3936 }
3937 for (; i < 9; ++i)
3938 matrix[i] = 0;
3939 matrixp = matrix;
3940 }
3941 RETVAL = i_new_fill_image(src, matrixp, xoff, yoff, combine);
3942 OUTPUT:
3943 RETVAL
042cdaea 3944
a8652edf
TC
3945MODULE = Imager PACKAGE = Imager::Internal::Hlines PREFIX=i_int_hlines_
3946
3947# this class is only exposed for testing
3948
3949int
3950i_int_hlines_testing()
3951
3952#if i_int_hlines_testing()
3953
3954Imager::Internal::Hlines
3955i_int_hlines_new(start_y, count_y, start_x, count_x)
8d14daab 3956 i_img_dim start_y
a8652edf 3957 int count_y
8d14daab 3958 i_img_dim start_x