X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/0e2999c73c92818a8622641520540d050b42cdf8..e1c0692925:/Imager.xs diff --git a/Imager.xs b/Imager.xs index 87fbcc6a..58d92aa4 100644 --- a/Imager.xs +++ b/Imager.xs @@ -21,6 +21,7 @@ extern "C" { #include "regmach.h" #include "imextdef.h" #include "imextpltypes.h" +#include "imperlio.h" #include #if i_int_hlines_testing() @@ -29,13 +30,62 @@ extern "C" { #include "imperl.h" -static im_context_t work_context; +#define ARRAY_COUNT(array) (sizeof(array)/sizeof(*array)) + +/* + +Context object management + +*/ + +typedef im_context_t Imager__Context; + +#define im_context_DESTROY(ctx) im_context_refdec((ctx), "DESTROY") + +#ifdef PERL_IMPLICIT_CONTEXT + +#define MY_CXT_KEY "Imager::_context" XS_VERSION + +typedef struct { + im_context_t ctx; +} my_cxt_t; + +START_MY_CXT + +static void +start_context(pTHX) { + dMY_CXT; + MY_CXT.ctx = im_context_new(); + sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx); +} + +static im_context_t +perl_get_context(void) { + dTHX; + dMY_CXT; + + return MY_CXT.ctx; +} + +#else + +static im_context_t perl_context; + +static void +start_context(pTHX) { + perl_context = im_context_new(); + + /* just so it gets destroyed */ + sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", perl_context); +} static im_context_t perl_get_context(void) { - return work_context; + return perl_context; } +#endif + /* used to represent channel lists parameters */ typedef struct i_channel_list_tag { int *channels; @@ -52,6 +102,11 @@ typedef struct { const i_fsample_t *samples; } i_fsample_list; +typedef struct { + size_t count; + const i_polygon_t *polygons; +} i_polygon_list; + /* Allocate memory that will be discarded when mortals are discarded. @@ -60,9 +115,42 @@ Allocate memory that will be discarded when mortals are discarded. static void * malloc_temp(pTHX_ size_t size) { - SV *sv = sv_2mortal(newSV(size)); + void *result; + Newx(result, size, char); + SAVEFREEPV(result); + + return result; +} + +static void * +calloc_temp(pTHX_ size_t size) { + void *result; + Newxz(result, size, char); + SAVEFREEPV(result); + + return result; +} + +/* for use with the T_AVARRAY typemap */ +#define doublePtr(size) ((double *)calloc_temp(aTHX_ sizeof(double) * (size))) +#define SvDouble(sv, pname) (SvNV(sv)) - return SvPVX(sv); +#define intPtr(size) ((int *)calloc_temp(aTHX_ sizeof(int) * (size))) +#define SvInt(sv, pname) (SvIV(sv)) + +#define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size))) +#define SvI_img_dim(sv, pname) (SvIV(sv)) + +#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color) * (size))) + +#define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname) + +static i_color +S_sv_to_i_color(pTHX_ SV *sv, const char *pname) { + if (!sv_derived_from(sv, "Imager::Color")) { + croak("%s: not a color object", pname); + } + return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv))); } /* These functions are all shared - then comes platform dependant code */ @@ -147,9 +235,9 @@ static int getobj(void *hv_t,char *key,char *type,void **store) { UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj}; -void my_SvREFCNT_dec(void *p) { - dTHX; - SvREFCNT_dec((SV*)p); +static void +free_buffer(void *p) { + myfree(p); } @@ -324,7 +412,6 @@ static int io_closer(void *p) { if (SvOK(cbd->closecb)) { dSP; I32 count; - SV *sv; ENTER; SAVETMPS; @@ -335,8 +422,12 @@ static int io_closer(void *p) { SPAGAIN; - sv = POPs; - success = SvTRUE(sv); + if (count) { + SV *sv = POPs; + success = SvTRUE(sv); + } + else + success = 0; PUTBACK; FREETMPS; @@ -357,14 +448,26 @@ static void io_destroyer(void *p) { myfree(cbd); } -static i_io_glue_t * -do_io_new_buffer(pTHX_ SV *data_sv) { - const char *data; - STRLEN length; +static bool +im_SvREFSCALAR(SV *sv) { + svtype type = SvTYPE(sv); + + switch (type) { + case SVt_PV: + case SVt_PVIV: + case SVt_PVNV: + case SVt_PVMG: + case SVt_IV: + case SVt_NV: + case SVt_PVLV: +#if PERL_VERSION > 10 + case SVt_REGEXP: +#endif + return 1; - data = SvPVbyte(data_sv, length); - SvREFCNT_inc(data_sv); - return io_new_buffer(data, length, my_SvREFCNT_dec, data_sv); + default: + return 0; + } } static const char * @@ -388,6 +491,35 @@ describe_sv(SV *sv) { } } +static i_io_glue_t * +do_io_new_buffer(pTHX_ SV *data_sv) { + const char *data; + char *data_copy; + STRLEN length; + SV *sv; + + SvGETMAGIC(data_sv); + if (SvROK(data_sv)) { + if (im_SvREFSCALAR(SvRV(data_sv))) { + sv = SvRV(data_sv); + } + else { + i_push_errorf(0, "data is not a scalar or a reference to scalar"); + return NULL; + } + } + else { + sv = data_sv; + } + + /* previously this would keep the SV around, but this is unsafe in + many ways, so always copy the bytes */ + data = SvPVbyte(sv, length); + data_copy = mymalloc(length); + memcpy(data_copy, data, length); + return io_new_buffer(data_copy, length, free_buffer, data_copy); +} + static i_io_glue_t * do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) { struct cbdata *cbd; @@ -405,18 +537,29 @@ do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) { } struct value_name { - char *name; + const char *name; int value; }; -static int lookup_name(struct value_name *names, int count, char *name, int def_value) +static int +lookup_name(const struct value_name *names, int count, char *name, int def_value, int push_errors, const char *id, int *failed) { int i; + + if (push_errors) + *failed = 0; + for (i = 0; i < count; ++i) if (strEQ(names[i].name, name)) return names[i].value; + if (push_errors) { + i_push_errorf(0, "unknown value '%s' for %s", name, id); + *failed = 1; + } + return def_value; } + static struct value_name transp_names[] = { { "none", tr_none }, @@ -470,14 +613,14 @@ static struct value_name orddith_names[] = }; /* look through the hash for quantization options */ -static void -ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) +static int +ip_handle_quant_opts_low(pTHX_ i_quantize *quant, HV *hv, int push_errors) { - /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/ SV **sv; int i; STRLEN len; char *str; + int failed = 0; quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color)); @@ -485,7 +628,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) if (sv && *sv && (str = SvPV(*sv, len))) { quant->transp = lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names), - str, tr_none); + str, tr_none, push_errors, "transp", &failed); + if (failed) + return 0; if (quant->transp != tr_none) { quant->tr_threshold = 127; sv = hv_fetch(hv, "tr_threshold", 12, 0); @@ -495,13 +640,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) if (quant->transp == tr_errdiff) { sv = hv_fetch(hv, "tr_errdiff", 10, 0); if (sv && *sv && (str = SvPV(*sv, len))) - quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd); + quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "tr_errdiff", &failed); + if (failed) + return 0; } if (quant->transp == tr_ordered) { quant->tr_orddith = od_tiny; sv = hv_fetch(hv, "tr_orddith", 10, 0); - if (sv && *sv && (str = SvPV(*sv, len))) - quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random); + if (sv && *sv && (str = SvPV(*sv, len))) { + quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random, push_errors, "tr_orddith", &failed); + if (failed) + return 0; + } if (quant->tr_orddith == od_custom) { sv = hv_fetch(hv, "tr_map", 6, 0); @@ -526,7 +676,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) sv = hv_fetch(hv, "make_colors", 11, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->make_colors = - lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut); + lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut, push_errors, "make_colors", &failed); + if (failed) + return 0; } sv = hv_fetch(hv, "colors", 6, 0); if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { @@ -543,6 +695,10 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1))); quant->mc_colors[i] = *col; } + else if (push_errors) { + i_push_errorf(0, "colors[%d] isn't an Imager::Color object", i); + return 0; + } } } sv = hv_fetch(hv, "max_colors", 10, 0); @@ -555,11 +711,15 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) quant->translate = pt_closest; sv = hv_fetch(hv, "translate", 9, 0); if (sv && *sv && (str = SvPV(*sv, len))) { - quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest); + quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest, push_errors, "translate", &failed); + if (failed) + return 0; } sv = hv_fetch(hv, "errdiff", 7, 0); if (sv && *sv && (str = SvPV(*sv, len))) { - quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd); + quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "errdiff", &failed); + if (failed) + return 0; } if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) { /* get the error diffusion map */ @@ -584,7 +744,12 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) for (i = 0; i < len; ++i) { SV **sv2 = av_fetch(av, i, 0); if (sv2 && *sv2) { - quant->ed_map[i] = SvIV(*sv2); + IV iv = SvIV(*sv2); + if (push_errors && iv < 0) { + i_push_errorf(0, "errdiff_map values must be non-negative, errdiff[%d] is negative", i); + return 0; + } + quant->ed_map[i] = iv; sum += quant->ed_map[i]; } } @@ -594,12 +759,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) myfree(quant->ed_map); quant->ed_map = 0; quant->errdiff = ed_floyd; + if (push_errors) { + i_push_error(0, "error diffusion map must contain some non-zero values"); + return 0; + } } } } sv = hv_fetch(hv, "perturb", 7, 0); if (sv && *sv) quant->perturb = SvIV(*sv); + + return 1; } static void @@ -609,6 +780,20 @@ ip_cleanup_quant_opts(pTHX_ i_quantize *quant) { myfree(quant->ed_map); } +static int +ip_handle_quant_opts2(pTHX_ i_quantize *quant, HV *hv) { + int result = ip_handle_quant_opts_low(aTHX_ quant, hv, 1); + if (!result) { + ip_cleanup_quant_opts(aTHX_ quant); + } + return result; +} + +static void +ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) { + (void)ip_handle_quant_opts_low(aTHX_ quant, hv, 0); +} + /* copies the color map from the hv into the colors member of the HV */ static void ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) { @@ -636,6 +821,95 @@ ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) { } } +static struct value_name +poly_fill_mode_names[] = +{ + { "evenodd", i_pfm_evenodd }, + { "nonzero", i_pfm_nonzero } +}; + +static i_poly_fill_mode_t +S_get_poly_fill_mode(pTHX_ SV *sv) { + if (looks_like_number(sv)) { + IV work = SvIV(sv); + if (work < (IV)i_pfm_evenodd || work > (IV)i_pfm_nonzero) + work = (IV)i_pfm_evenodd; + return (i_poly_fill_mode_t)work; + } + else { + return (i_poly_fill_mode_t)lookup_name + (poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names), + SvPV_nolen(sv), i_pfm_evenodd, 0, NULL, NULL); + } +} + +static void +S_get_polygon_list(pTHX_ i_polygon_list *polys, SV *sv) { + AV *av; + int i; + i_polygon_t *s; + + SvGETMAGIC(sv); + if (!SvOK(sv) || !SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV) + croak("polys must be an arrayref"); + + av = (AV*)SvRV(sv); + polys->count = av_len(av) + 1; + if (polys->count < 1) + croak("polypolygon: no polygons provided"); + s = malloc_temp(aTHX_ sizeof(i_polygon_t) * polys->count); + for (i = 0; i < polys->count; ++i) { + SV **poly_sv = av_fetch(av, i, 0); + AV *poly_av; + SV **x_sv, **y_sv; + AV *x_av, *y_av; + double *x_data, *y_data; + ssize_t j; + ssize_t point_count; + + if (!poly_sv) + croak("poly_polygon: nothing found for polygon %d", i); + /* needs to be another av */ + SvGETMAGIC(*poly_sv); + if (!SvOK(*poly_sv) || !SvROK(*poly_sv) || SvTYPE(SvRV(*poly_sv)) != SVt_PVAV) + croak("poly_polygon: polygon %d isn't an arrayref", i); + poly_av = (AV*)SvRV(*poly_sv); + /* with two elements */ + if (av_len(poly_av) != 1) + croak("poly_polygon: polygon %d should contain two arrays", i); + x_sv = av_fetch(poly_av, 0, 0); + y_sv = av_fetch(poly_av, 1, 0); + if (!x_sv) + croak("poly_polygon: polygon %d has no x elements", i); + if (!y_sv) + croak("poly_polygon: polygon %d has no y elements", i); + SvGETMAGIC(*x_sv); + SvGETMAGIC(*y_sv); + if (!SvOK(*x_sv) || !SvROK(*x_sv) || SvTYPE(SvRV(*x_sv)) != SVt_PVAV) + croak("poly_polygon: polygon %d x elements isn't an array", i); + if (!SvOK(*y_sv) || !SvROK(*y_sv) || SvTYPE(SvRV(*y_sv)) != SVt_PVAV) + croak("poly_polygon: polygon %d y elements isn't an array", i); + x_av = (AV*)SvRV(*x_sv); + y_av = (AV*)SvRV(*y_sv); + if (av_len(x_av) != av_len(y_av)) + croak("poly_polygon: polygon %d x and y arrays different lengths", i+1); + point_count = av_len(x_av)+1; + x_data = malloc_temp(aTHX_ sizeof(double) * point_count * 2); + y_data = x_data + point_count; + + for (j = 0; j < point_count; ++j) { + SV **x_item_sv = av_fetch(x_av, j, 0); + SV **y_item_sv = av_fetch(y_av, j, 0); + x_data[j] = x_item_sv ? SvNV(*x_item_sv) : 0; + y_data[j] = y_item_sv ? SvNV(*y_item_sv) : 0; + } + s[i].x = x_data; + s[i].y = y_data; + s[i].count = point_count; + } + polys->polygons = s; +} + /* loads the segments of a fountain fill into an array */ static i_fountain_seg * load_fount_segs(pTHX_ AV *asegs, int *count) { @@ -734,7 +1008,6 @@ validate_i_ppal(i_img *im, i_palidx const *indexes, int count) { } } - /* I don't think ICLF_* names belong at the C interface this makes the XS code think we have them, to let us avoid putting function bodies in the XS code @@ -836,7 +1109,8 @@ static im_pl_ext_funcs im_perl_funcs = IMAGER_PL_API_LEVEL, ip_handle_quant_opts, ip_cleanup_quant_opts, - ip_copy_colors_back + ip_copy_colors_back, + ip_handle_quant_opts2 }; #define PERL_PL_SET_GLOBAL_CALLBACKS \ @@ -844,6 +1118,7 @@ static im_pl_ext_funcs im_perl_funcs = #define IIM_new i_img_8_new #define IIM_DESTROY i_img_destroy +typedef int SysRet; #ifdef IMEXIF_ENABLE #define i_exif_enabled() 1 @@ -884,7 +1159,10 @@ ICL_set_internal(cl,r,g,b,a) unsigned char b unsigned char a PPCODE: - ICL_set_internal(cl, r, g, b, a); + cl->rgba.r = r; + cl->rgba.g = g; + cl->rgba.b = b; + cl->rgba.a = a; EXTEND(SP, 1); PUSHs(ST(0)); @@ -898,10 +1176,10 @@ ICL_rgba(cl) Imager::Color cl PPCODE: EXTEND(SP, 4); - PUSHs(sv_2mortal(newSVnv(cl->rgba.r))); - PUSHs(sv_2mortal(newSVnv(cl->rgba.g))); - PUSHs(sv_2mortal(newSVnv(cl->rgba.b))); - PUSHs(sv_2mortal(newSVnv(cl->rgba.a))); + PUSHs(sv_2mortal(newSViv(cl->rgba.r))); + PUSHs(sv_2mortal(newSViv(cl->rgba.g))); + PUSHs(sv_2mortal(newSViv(cl->rgba.b))); + PUSHs(sv_2mortal(newSViv(cl->rgba.a))); Imager::Color i_hsv_to_rgb(c) @@ -929,10 +1207,10 @@ MODULE = Imager PACKAGE = Imager::Color::Float PREFIX=ICLF_ Imager::Color::Float ICLF_new_internal(r, g, b, a) - double r - double g - double b - double a + im_double r + im_double g + im_double b + im_double a void ICLF_DESTROY(cl) @@ -953,10 +1231,10 @@ ICLF_rgba(cl) void ICLF_set_internal(cl,r,g,b,a) Imager::Color::Float cl - double r - double g - double b - double a + im_double r + im_double g + im_double b + im_double a PPCODE: cl->rgba.r = r; cl->rgba.g = g; @@ -988,9 +1266,9 @@ i_rgb_to_hsv(c) MODULE = Imager PACKAGE = Imager::ImgRaw PREFIX = IIM_ Imager::ImgRaw -IIM_new(x,y,ch) - i_img_dim x - i_img_dim y +IIM_new(xsize,ysize,ch) + i_img_dim xsize + i_img_dim ysize int ch void @@ -1016,7 +1294,10 @@ Imager::IO io_new_buffer(data_sv) SV *data_sv CODE: + i_clear_error(); RETVAL = do_io_new_buffer(aTHX_ data_sv); + if (!RETVAL) + XSRETURN(0); OUTPUT: RETVAL @@ -1026,7 +1307,6 @@ io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE) SV *readcb; SV *seekcb; SV *closecb; - int maxwrite; CODE: RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb); OUTPUT: @@ -1088,7 +1368,10 @@ Imager::IO io_new_buffer(class, data_sv) SV *data_sv CODE: + i_clear_error(); RETVAL = do_io_new_buffer(aTHX_ data_sv); + if (!RETVAL) + XSRETURN(0); OUTPUT: RETVAL @@ -1110,6 +1393,14 @@ io_new_bufchain(class) OUTPUT: RETVAL +Imager::IO +io__new_perlio(class, io) + PerlIO *io + CODE: + RETVAL = im_io_new_perlio(aTHX_ io); + OUTPUT: + RETVAL + SV * io_slurp(class, ig) Imager::IO ig @@ -1134,14 +1425,7 @@ i_io_raw_write(ig, data_sv) void *data; STRLEN size; CODE: -#ifdef SvUTF8 - if (SvUTF8(data_sv)) { - data_sv = sv_2mortal(newSVsv(data_sv)); - /* yes, we want this to croak() if the SV can't be downgraded */ - sv_utf8_downgrade(data_sv, FALSE); - } -#endif - data = SvPV(data_sv, size); + data = SvPVbyte(data_sv, size); RETVAL = i_io_raw_write(ig, data, size); OUTPUT: RETVAL @@ -1158,12 +1442,12 @@ i_io_raw_read(ig, buffer_sv, size) if (size <= 0) croak("size negative in call to i_io_raw_read()"); /* prevent an undefined value warning if they supplied an - undef buffer. + undef buffer. Orginally conditional on !SvOK(), but this will prevent the - downgrade from croaking */ - sv_setpvn(buffer_sv, "", 0); + downgrade from croaking */ + sv_setpvn(buffer_sv, "", 0); #ifdef SvUTF8 - if (SvUTF8(buffer_sv)) + if (SvUTF8(buffer_sv)) sv_utf8_downgrade(buffer_sv, FALSE); #endif buffer = SvGROW(buffer_sv, size+1); @@ -1230,6 +1514,10 @@ int i_io_getc(ig) Imager::IO ig +void +i_io_nextc(ig) + Imager::IO ig + int i_io_putc(ig, c) Imager::IO ig @@ -1289,12 +1577,12 @@ i_io_read(ig, buffer_sv, size) if (size <= 0) croak("size negative in call to i_io_read()"); /* prevent an undefined value warning if they supplied an - undef buffer. + undef buffer. Orginally conditional on !SvOK(), but this will prevent the - downgrade from croaking */ - sv_setpvn(buffer_sv, "", 0); + downgrade from croaking */ + sv_setpvn(buffer_sv, "", 0); #ifdef SvUTF8 - if (SvUTF8(buffer_sv)) + if (SvUTF8(buffer_sv)) sv_utf8_downgrade(buffer_sv, FALSE); #endif buffer = SvGROW(buffer_sv, size+1); @@ -1366,14 +1654,7 @@ i_io_write(ig, data_sv) void *data; STRLEN size; CODE: -#ifdef SvUTF8 - if (SvUTF8(data_sv)) { - data_sv = sv_2mortal(newSVsv(data_sv)); - /* yes, we want this to croak() if the SV can't be downgraded */ - sv_utf8_downgrade(data_sv, FALSE); - } -#endif - data = SvPV(data_sv, size); + data = SvPVbyte(data_sv, size); RETVAL = i_io_write(ig, data, size); OUTPUT: RETVAL @@ -1494,6 +1775,22 @@ IV i_img_get_height(im) Imager::ImgRaw im +int +i_img_color_model(im) + Imager::ImgRaw im + +int +i_img_color_channels(im) + Imager::ImgRaw im + +int +i_img_alpha_channel(im) + Imager::ImgRaw im + CODE: + if (!i_img_alpha_channel(im, &RETVAL)) + XSRETURN(0); + OUTPUT: + RETVAL void i_img_is_monochrome(im) @@ -1576,19 +1873,19 @@ i_arc(im,x,y,rad,d1,d2,val) Imager::ImgRaw im i_img_dim x i_img_dim y - double rad - double d1 - double d2 + im_double rad + im_double d1 + im_double d2 Imager::Color val void i_arc_aa(im,x,y,rad,d1,d2,val) Imager::ImgRaw im - double x - double y - double rad - double d1 - double d2 + im_double x + im_double y + im_double rad + im_double d1 + im_double d2 Imager::Color val void @@ -1596,30 +1893,38 @@ i_arc_cfill(im,x,y,rad,d1,d2,fill) Imager::ImgRaw im i_img_dim x i_img_dim y - double rad - double d1 - double d2 + im_double rad + im_double d1 + im_double d2 Imager::FillHandle fill void i_arc_aa_cfill(im,x,y,rad,d1,d2,fill) Imager::ImgRaw im - double x - double y - double rad - double d1 - double d2 + im_double x + im_double y + im_double rad + im_double d1 + im_double d2 Imager::FillHandle fill void i_circle_aa(im,x,y,rad,val) Imager::ImgRaw im - double x - double y - double rad + im_double x + im_double y + im_double rad Imager::Color val +void +i_circle_aa_fill(im,x,y,rad,fill) + Imager::ImgRaw im + im_double x + im_double y + im_double rad + Imager::FillHandle fill + int i_circle_out(im,x,y,rad,val) Imager::ImgRaw im @@ -1642,8 +1947,8 @@ i_arc_out(im,x,y,rad,d1,d2,val) i_img_dim x i_img_dim y i_img_dim rad - double d1 - double d2 + im_double d1 + im_double d2 Imager::Color val int @@ -1652,118 +1957,80 @@ i_arc_out_aa(im,x,y,rad,d1,d2,val) i_img_dim x i_img_dim y i_img_dim rad - double d1 - double d2 + im_double d1 + im_double d2 Imager::Color val void -i_bezier_multi(im,xc,yc,val) +i_bezier_multi(im,x,y,val) Imager::ImgRaw im - Imager::Color val - PREINIT: - double *x,*y; - int len; - AV *av1; - AV *av2; - SV *sv1; - SV *sv2; - int i; - PPCODE: - ICL_info(val); - if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n"); - if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n"); - av1=(AV*)SvRV(ST(1)); - av2=(AV*)SvRV(ST(2)); - if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n"); - len=av_len(av1)+1; - x=mymalloc( len*sizeof(double) ); - y=mymalloc( len*sizeof(double) ); - for(i=0;i 9) - len = 9; - for (i = 0; i < len; ++i) { - sv1=(*(av_fetch(av,i,0))); - matrix[i] = SvNV(sv1); - } - for (; i < 9; ++i) - matrix[i] = 0; - /* extract the bg colors if any */ - /* yes, this is kind of strange */ - for (i = 4; i < items; ++i) { - sv1 = ST(i); - if (sv_derived_from(sv1, "Imager::Color")) { - IV tmp = SvIV((SV*)SvRV(sv1)); - backp = INT2PTR(i_color *, tmp); - } - else if (sv_derived_from(sv1, "Imager::Color::Float")) { - IV tmp = SvIV((SV*)SvRV(sv1)); - fbackp = INT2PTR(i_fcolor *, tmp); - } - } - RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp); - OUTPUT: - RETVAL + i_img_dim xsize + i_img_dim ysize + AV *matrix_av + PREINIT: + double matrix[9]; + STRLEN len; + SV *sv1; + int i; + i_color *backp = NULL; + i_fcolor *fbackp = NULL; + CODE: + len=av_len(matrix_av)+1; + if (len > 9) + len = 9; + for (i = 0; i < len; ++i) { + sv1=(*(av_fetch(matrix_av,i,0))); + matrix[i] = SvNV(sv1); + } + for (; i < 9; ++i) + matrix[i] = 0; + /* extract the bg colors if any */ + /* yes, this is kind of strange */ + for (i = 4; i < items; ++i) { + sv1 = ST(i); + if (sv_derived_from(sv1, "Imager::Color")) { + IV tmp = SvIV((SV*)SvRV(sv1)); + backp = INT2PTR(i_color *, tmp); + } + else if (sv_derived_from(sv1, "Imager::Color::Float")) { + IV tmp = SvIV((SV*)SvRV(sv1)); + fbackp = INT2PTR(i_fcolor *, tmp); + } + } + RETVAL = i_matrix_transform_bg(im, xsize, ysize, matrix, backp, fbackp); + OUTPUT: + RETVAL undef_int i_gaussian(im,stdev) Imager::ImgRaw im - double stdev + im_double stdev void i_unsharp_mask(im,stdev,scale) Imager::ImgRaw im - double stdev - double scale + im_double stdev + im_double scale int i_conv(im,coef) @@ -2042,6 +2306,10 @@ i_convert(src, avmain) if (len > inchan) inchan = len; } + else { + i_push_errorf(0, "invalid matrix: element %d is not an array ref", j); + XSRETURN(0); + } } coeff = mymalloc(sizeof(double) * outchan * inchan); for (j = 0; j < outchan; ++j) { @@ -2063,46 +2331,44 @@ i_convert(src, avmain) RETVAL -void -i_map(im, pmaps) +undef_int +i_map(im, pmaps_av) Imager::ImgRaw im - PREINIT: - unsigned int mask = 0; - AV *avmain; - AV *avsub; - SV **temp; - int len; - int i, j; - unsigned char (*maps)[256]; - CODE: - if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) - croak("i_map: parameter 2 must be an arrayref\n"); - avmain = (AV*)SvRV(ST(1)); - len = av_len(avmain)+1; - if (im->channels < len) len = im->channels; - - maps = mymalloc( len * sizeof(unsigned char [256]) ); - - for (j=0; j255) val = 255; - maps[j][i] = val; - } - } - } - i_map(im, maps, mask); - myfree(maps); - - + AV *pmaps_av + PREINIT: + unsigned int mask = 0; + AV *avsub; + SV **temp; + int len; + int i, j; + unsigned char (*maps)[256]; + CODE: + len = av_len(pmaps_av)+1; + if (im->channels < len) + len = im->channels; + maps = mymalloc( len * sizeof(unsigned char [256]) ); + for (j=0; j255) val = 255; + maps[j][i] = val; + } + } + } + i_map(im, maps, mask); + myfree(maps); + RETVAL = 1; + OUTPUT: + RETVAL float i_img_diff(im1,im2) @@ -2118,7 +2384,7 @@ int i_img_samef(im1, im2, epsilon = i_img_epsilonf(), what=NULL) Imager::ImgRaw im1 Imager::ImgRaw im2 - double epsilon + im_double epsilon const char *what double @@ -2164,13 +2430,13 @@ MODULE = Imager PACKAGE = Imager undef_int -i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1) +i_tt_text(handle,im,xb,yb,cl,points,str_sv,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im i_img_dim xb i_img_dim yb Imager::Color cl - double points + im_double points SV * str_sv int smooth int utf8 @@ -2179,11 +2445,11 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1) char *str; STRLEN len; CODE: + str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif - str = SvPV(str_sv, len); RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, len, smooth, utf8, align); OUTPUT: @@ -2191,13 +2457,13 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1) undef_int -i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1) +i_tt_cp(handle,im,xb,yb,channel,points,str_sv,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im i_img_dim xb i_img_dim yb int channel - double points + im_double points SV * str_sv int smooth int utf8 @@ -2206,11 +2472,11 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1) char *str; STRLEN len; CODE: + str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif - str = SvPV(str_sv, len); RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len, smooth, utf8, align); OUTPUT: @@ -2218,9 +2484,9 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1) void -i_tt_bbox(handle,point,str_sv,len_ignored, utf8) +i_tt_bbox(handle,point,str_sv,utf8) Imager::Font::TT handle - double point + im_double point SV* str_sv int utf8 PREINIT: @@ -2230,11 +2496,11 @@ i_tt_bbox(handle,point,str_sv,len_ignored, utf8) STRLEN len; int i; PPCODE: + str = SvPV(str_sv, len); #ifdef SvUTF8 if (SvUTF8(ST(2))) utf8 = 1; #endif - str = SvPV(str_sv, len); if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) { EXTEND(SP, rc); for (i = 0; i < rc; ++i) { @@ -2254,18 +2520,21 @@ i_tt_has_chars(handle, text_sv, utf8) size_t count; size_t i; PPCODE: + i_clear_error(); + text = SvPV(text_sv, len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif - text = SvPV(text_sv, len); work = mymalloc(len); count = i_tt_has_chars(handle, text, len, utf8, work); if (GIMME_V == G_ARRAY) { - EXTEND(SP, count); - for (i = 0; i < count; ++i) { - PUSHs(boolSV(work[i])); - } + if (count) { + EXTEND(SP, count); + for (i = 0; i < count; ++i) { + PUSHs(boolSV(work[i])); + } + } } else { EXTEND(SP, 1); @@ -2302,11 +2571,12 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0) size_t outsize; char name[255]; PPCODE: + i_clear_error(); + text = SvPV(text_sv, work_len); #ifdef SvUTF8 if (SvUTF8(text_sv)) utf8 = 1; #endif - text = SvPV(text_sv, work_len); len = work_len; while (len) { unsigned long ch; @@ -2314,7 +2584,7 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0) ch = i_utf8_advance(&text, &len); if (ch == ~0UL) { i_push_error(0, "invalid UTF8 character"); - break; + XSRETURN_EMPTY; } } else { @@ -2323,11 +2593,11 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0) } EXTEND(SP, 1); if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) { - PUSHs(sv_2mortal(newSVpv(name, 0))); + PUSHs(sv_2mortal(newSVpv(name, 0))); } else { - PUSHs(&PL_sv_undef); - } + PUSHs(&PL_sv_undef); + } } #endif @@ -2424,14 +2694,14 @@ i_readtga_wiol(ig, length) Imager::ImgRaw i_scaleaxis(im,Value,Axis) Imager::ImgRaw im - double Value + im_double Value int Axis Imager::ImgRaw i_scale_nn(im,scx,scy) Imager::ImgRaw im - double scx - double scy + im_double scx + im_double scy Imager::ImgRaw i_scale_mixing(im, width, height) @@ -2458,60 +2728,27 @@ i_get_anonymous_color_histo(im, maxc = 0x40000000) int col_cnt; PPCODE: col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc); + if (col_cnt <= 0) { + XSRETURN_EMPTY; + } EXTEND(SP, col_cnt); for (i = 0; i < col_cnt; i++) { PUSHs(sv_2mortal(newSViv( col_usage[i]))); } myfree(col_usage); - XSRETURN(col_cnt); void -i_transform(im,opx,opy,parm) +i_transform(im, opx, opy, parm) Imager::ImgRaw im + int *opx + int *opy + double *parm PREINIT: - double* parm; - int *opx; - int *opy; - int opxl; - int opyl; - int parmlen; - AV* av; - SV* sv1; - int i; + STRLEN size_opx, size_opy, size_parm; i_img *result; PPCODE: - if (!SvROK(ST(1))) croak("Imager: Parameter 1 must be a reference to an array\n"); - if (!SvROK(ST(2))) croak("Imager: Parameter 2 must be a reference to an array\n"); - if (!SvROK(ST(3))) croak("Imager: Parameter 3 must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 3 must be a reference to an array\n"); - av=(AV*)SvRV(ST(1)); - opxl=av_len(av)+1; - opx=mymalloc( opxl*sizeof(int) ); - for(i=0;i 3) - croak("i_getcolors: too many arguments"); - if (items == 3) - count = SvIV(ST(2)); if (count < 1) croak("i_getcolors: count must be positive"); - colors = mymalloc(sizeof(i_color) * count); + colors = malloc_temp(aTHX_ sizeof(i_color) * count); if (i_getcolors(im, index, colors, count)) { + EXTEND(SP, count); for (i = 0; i < count; ++i) { SV *sv = make_i_color_sv(aTHX_ colors+i); PUSHs(sv); } } - myfree(colors); - undef_neg_int i_colorcount(im) @@ -3226,18 +3417,13 @@ undef_neg_int i_maxcolors(im) Imager::ImgRaw im -SV * +i_palidx i_findcolor(im, color) Imager::ImgRaw im Imager::Color color - PREINIT: - i_palidx index; CODE: - if (i_findcolor(im, color, &index)) { - RETVAL = newSViv(index); - } - else { - RETVAL = &PL_sv_undef; + if (!i_findcolor(im, color, &RETVAL)) { + XSRETURN_UNDEF; } OUTPUT: RETVAL @@ -3266,7 +3452,7 @@ i_gsamp(im, l, r, y, channels) i_img_dim count, i; PPCODE: if (l < r) { - data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); /* XXX: memleak? */ + data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); count = i_gsamp(im, l, r, y, data, channels.channels, channels.count); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); @@ -3281,8 +3467,7 @@ i_gsamp(im, l, r, y, channels) } else { if (GIMME_V != G_ARRAY) { - EXTEND(SP, 1); - PUSHs(&PL_sv_undef); + XSRETURN_UNDEF; } } @@ -3530,8 +3715,7 @@ i_gsampf(im, l, r, y, channels) } else { if (GIMME_V != G_ARRAY) { - EXTEND(SP, 1); - PUSHs(&PL_sv_undef); + XSRETURN_UNDEF; } } @@ -3580,22 +3764,17 @@ i_plinf(im, l, y, ...) OUTPUT: RETVAL -SV * +Imager::Color::Float i_gpixf(im, x, y) Imager::ImgRaw im i_img_dim x i_img_dim y; - PREINIT: - i_fcolor *color; CODE: - color = (i_fcolor *)mymalloc(sizeof(i_fcolor)); - if (i_gpixf(im, x, y, color) == 0) { - RETVAL = NEWSV(0,0); - sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color); - } - else { - myfree(color); - RETVAL = &PL_sv_undef; + RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor)); + memset(RETVAL, 0, sizeof(*RETVAL)); + if (i_gpixf(im, x, y, RETVAL) != 0) { + myfree(RETVAL); + XSRETURN_UNDEF; } OUTPUT: RETVAL @@ -3665,42 +3844,44 @@ i_glinf(im, l, r, y) } Imager::ImgRaw -i_img_8_new(x, y, ch) - i_img_dim x - i_img_dim y - int ch +i_img_8_new(xsize, ysize, channels) + i_img_dim xsize + i_img_dim ysize + int channels Imager::ImgRaw -i_img_16_new(x, y, ch) - i_img_dim x - i_img_dim y - int ch +i_img_16_new(xsize, ysize, channels) + i_img_dim xsize + i_img_dim ysize + int channels Imager::ImgRaw i_img_to_rgb16(im) Imager::ImgRaw im Imager::ImgRaw -i_img_double_new(x, y, ch) - i_img_dim x - i_img_dim y - int ch +i_img_double_new(xsize, ysize, channels) + i_img_dim xsize + i_img_dim ysize + int channels Imager::ImgRaw i_img_to_drgb(im) Imager::ImgRaw im undef_int -i_tags_addn(im, name, code, idata) +i_tags_addn(im, name_sv, code, idata) Imager::ImgRaw im + SV *name_sv int code int idata PREINIT: char *name; STRLEN len; CODE: - if (SvOK(ST(1))) - name = SvPV(ST(1), len); + SvGETMAGIC(name_sv); + if (SvOK(name_sv)) + name = SvPV_nomg(name_sv, len); else name = NULL; RETVAL = i_tags_addn(&im->tags, name, code, idata); @@ -3708,21 +3889,25 @@ i_tags_addn(im, name, code, idata) RETVAL undef_int -i_tags_add(im, name, code, data, idata) +i_tags_add(im, name_sv, code, data_sv, idata) Imager::ImgRaw im + SV *name_sv int code + SV *data_sv int idata PREINIT: char *name; char *data; STRLEN len; CODE: - if (SvOK(ST(1))) - name = SvPV(ST(1), len); + SvGETMAGIC(name_sv); + if (SvOK(name_sv)) + name = SvPV_nomg(name_sv, len); else name = NULL; - if (SvOK(ST(3))) - data = SvPV(ST(3), len); + SvGETMAGIC(data_sv); + if (SvOK(data_sv)) + data = SvPV(data_sv, len); else { data = NULL; len = 0; @@ -3731,7 +3916,7 @@ i_tags_add(im, name, code, data, idata) OUTPUT: RETVAL -SV * +SysRet i_tags_find(im, name, start) Imager::ImgRaw im char *name @@ -3740,17 +3925,14 @@ i_tags_find(im, name, start) int entry; CODE: if (i_tags_find(&im->tags, name, start, &entry)) { - if (entry == 0) - RETVAL = newSVpv("0 but true", 0); - else - RETVAL = newSViv(entry); + RETVAL = entry; } else { - RETVAL = &PL_sv_undef; + XSRETURN_UNDEF; } OUTPUT: RETVAL -SV * +SysRet i_tags_findn(im, code, start) Imager::ImgRaw im int code @@ -3759,13 +3941,10 @@ i_tags_findn(im, code, start) int entry; CODE: if (i_tags_findn(&im->tags, code, start, &entry)) { - if (entry == 0) - RETVAL = newSVpv("0 but true", 0); - else - RETVAL = newSViv(entry); + RETVAL = entry; } else { - RETVAL = &PL_sv_undef; + XSRETURN_UNDEF; } OUTPUT: RETVAL @@ -3879,19 +4058,21 @@ i_new_fill_solidf(cl, combine) int combine Imager::FillHandle -i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) +i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy) Imager::Color fg Imager::Color bg int combine int hatch + SV *cust_hatch_sv i_img_dim dx i_img_dim dy PREINIT: unsigned char *cust_hatch; STRLEN len; CODE: - if (SvOK(ST(4))) { - cust_hatch = (unsigned char *)SvPV(ST(4), len); + SvGETMAGIC(cust_hatch_sv); + if (SvOK(cust_hatch_sv)) { + cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len); } else cust_hatch = NULL; @@ -3900,19 +4081,21 @@ i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy) RETVAL Imager::FillHandle -i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) +i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy) Imager::Color::Float fg Imager::Color::Float bg int combine int hatch + SV *cust_hatch_sv i_img_dim dx i_img_dim dy PREINIT: unsigned char *cust_hatch; STRLEN len; CODE: - if (SvOK(ST(4))) { - cust_hatch = (unsigned char *)SvPV(ST(4), len); + SvGETMAGIC(cust_hatch_sv); + if (SvOK(cust_hatch_sv)) { + cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len); } else cust_hatch = NULL; @@ -3921,8 +4104,9 @@ i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy) RETVAL Imager::FillHandle -i_new_fill_image(src, matrix, xoff, yoff, combine) +i_new_fill_image(src, matrix_sv, xoff, yoff, combine) Imager::ImgRaw src + SV *matrix_sv i_img_dim xoff i_img_dim yoff int combine @@ -3934,13 +4118,14 @@ i_new_fill_image(src, matrix, xoff, yoff, combine) SV *sv1; int i; CODE: - if (!SvOK(ST(1))) { + SvGETMAGIC(matrix_sv); + if (!SvOK(matrix_sv)) { matrixp = NULL; } else { - if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) - croak("i_new_fill_image: parameter must be an arrayref"); - av=(AV*)SvRV(ST(1)); + if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV) + croak("i_new_fill_image: matrix parameter must be an arrayref or undef"); + av=(AV*)SvRV(matrix_sv); len=av_len(av)+1; if (len > 9) len = 9; @@ -3996,8 +4181,40 @@ i_int_hlines_CLONE_SKIP(cls) #endif +MODULE = Imager PACKAGE = Imager::Context PREFIX=im_context_ + +void +im_context_DESTROY(ctx) + Imager::Context ctx + +#ifdef PERL_IMPLICIT_CONTEXT + +void +im_context_CLONE(...) + CODE: + MY_CXT_CLONE; + (void)items; + /* the following sv_setref_pv() will free this inc */ + im_context_refinc(MY_CXT.ctx, "CLONE"); + MY_CXT.ctx = im_context_clone(MY_CXT.ctx, "CLONE"); + if (MY_CXT.ctx == NULL) { + croak("Failed to clone Imager context"); + } + sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx); + +#endif + BOOT: PERL_SET_GLOBAL_CALLBACKS; PERL_PL_SET_GLOBAL_CALLBACKS; - work_context = im_context_new(); +#ifdef PERL_IMPLICIT_CONTEXT + { + MY_CXT_INIT; + (void)MY_CXT; + } +#endif + start_context(aTHX); im_get_context = perl_get_context; +#ifdef HAVE_LIBTT + i_tt_start(); +#endif