X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/3631271bb7effc10ccbba79f603c848b30f4709c..4326b23a38b971802036792fd8af38076f1c3fae:/Imager.xs diff --git a/Imager.xs b/Imager.xs index b349641e..d1512c0c 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1,9 +1,12 @@ +#define PERL_NO_GET_CONTEXT #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" +#define NEED_newRV_noinc +#define NEED_sv_2pv_nolen #include "ppport.h" #ifdef __cplusplus } @@ -16,8 +19,7 @@ extern "C" { #include "dynaload.h" #include "regmach.h" #include "imextdef.h" - -typedef io_glue* Imager__IO; +#include "imextpltypes.h" #if i_int_hlines_testing() #include "imageri.h" @@ -27,6 +29,7 @@ typedef io_glue* Imager__IO; /* These functions are all shared - then comes platform dependant code */ static int getstr(void *hv_t,char *key,char **store) { + dTHX; SV** svpp; HV* hv=(HV*)hv_t; @@ -41,6 +44,7 @@ static int getstr(void *hv_t,char *key,char **store) { } static int getint(void *hv_t,char *key,int *store) { + dTHX; SV** svpp; HV* hv=(HV*)hv_t; @@ -54,6 +58,7 @@ static int getint(void *hv_t,char *key,int *store) { } static int getdouble(void *hv_t,char* key,double *store) { + dTHX; SV** svpp; HV* hv=(HV*)hv_t; @@ -66,6 +71,7 @@ static int getdouble(void *hv_t,char* key,double *store) { } static int getvoid(void *hv_t,char* key,void **store) { + dTHX; SV** svpp; HV* hv=(HV*)hv_t; @@ -80,6 +86,7 @@ static int getvoid(void *hv_t,char* key,void **store) { } static int getobj(void *hv_t,char *key,char *type,void **store) { + dTHX; SV** svpp; HV* hv=(HV*)hv_t; @@ -103,12 +110,13 @@ 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 -log_entry(char *string, int level) { +i_log_entry(char *string, int level) { mm_log((level, string)); } @@ -121,6 +129,7 @@ typedef struct i_reader_data_tag /* used by functions that want callbacks */ static int read_callback(char *userdata, char *buffer, int need, int want) { + dTHX; i_reader_data *rd = (i_reader_data *)userdata; int count; int result; @@ -172,6 +181,7 @@ typedef struct /* used by functions that want callbacks */ static int write_callback(char *userdata, char const *data, int size) { + dTHX; i_writer_data *wd = (i_writer_data *)userdata; int count; int success; @@ -243,6 +253,7 @@ Low-level function to call the perl writer callback. */ static ssize_t call_writer(struct cbdata *cbd, void const *buf, size_t size) { + dTHX; int count; int success; SV *sv; @@ -272,11 +283,12 @@ static ssize_t call_writer(struct cbdata *cbd, void const *buf, size_t size) { FREETMPS; LEAVE; - return success ? size : 0; + return success ? size : -1; } static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size, size_t maxread) { + dTHX; int count; int result; SV *data; @@ -323,14 +335,21 @@ static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size, } static ssize_t write_flush(struct cbdata *cbd) { + dTHX; ssize_t result; - result = call_writer(cbd, cbd->buffer, cbd->used); - cbd->used = 0; - return result; + if (cbd->used) { + result = call_writer(cbd, cbd->buffer, cbd->used); + cbd->used = 0; + return result; + } + else { + return 1; /* success of some sort */ + } } static off_t io_seeker(void *p, off_t offset, int whence) { + dTHX; struct cbdata *cbd = p; int count; off_t result; @@ -375,14 +394,14 @@ static off_t io_seeker(void *p, off_t offset, int whence) { } static ssize_t io_writer(void *p, void const *data, size_t size) { + dTHX; struct cbdata *cbd = p; - /*printf("io_writer(%p, %p, %u)\n", p, data, size);*/ + /* printf("io_writer(%p, %p, %u)\n", p, data, size); */ if (!cbd->writing) { if (cbd->reading && cbd->where < cbd->used) { /* we read past the place where the caller expected us to be so adjust our position a bit */ - *(char *)0 = 0; if (io_seeker(p, cbd->where - cbd->used, SEEK_CUR) < 0) { return -1; } @@ -392,8 +411,9 @@ static ssize_t io_writer(void *p, void const *data, size_t size) { } cbd->writing = 1; if (cbd->used && cbd->used + size > cbd->maxlength) { - if (write_flush(cbd) <= 0) { - return 0; + int write_res = write_flush(cbd); + if (write_res <= 0) { + return write_res; } cbd->used = 0; } @@ -406,11 +426,14 @@ static ssize_t io_writer(void *p, void const *data, size_t size) { return call_writer(cbd, data, size); } -static ssize_t io_reader(void *p, void *data, size_t size) { +static ssize_t +io_reader(void *p, void *data, size_t size) { + dTHX; struct cbdata *cbd = p; ssize_t total; char *out = data; /* so we can do pointer arithmetic */ + /* printf("io_reader(%p, %p, %d)\n", p, data, size); */ if (cbd->writing) { if (write_flush(cbd) <= 0) return 0; @@ -430,7 +453,7 @@ static ssize_t io_reader(void *p, void *data, size_t size) { size -= cbd->used - cbd->where; out += cbd->used - cbd->where; if (size < sizeof(cbd->buffer)) { - int did_read; + int did_read = 0; int copy_size; while (size && (did_read = call_reader(cbd, cbd->buffer, size, @@ -445,6 +468,8 @@ static ssize_t io_reader(void *p, void *data, size_t size) { total += copy_size; size -= copy_size; } + if (did_read < 0) + return -1; } else { /* just read the rest - too big for our buffer*/ @@ -454,16 +479,20 @@ static ssize_t io_reader(void *p, void *data, size_t size) { total += did_read; out += did_read; } + if (did_read < 0) + return -1; } return total; } -static void io_closer(void *p) { +static int io_closer(void *p) { + dTHX; struct cbdata *cbd = p; if (cbd->writing && cbd->used > 0) { - write_flush(cbd); + if (write_flush(cbd) < 0) + return -1; cbd->writing = 0; } @@ -482,9 +511,12 @@ static void io_closer(void *p) { FREETMPS; LEAVE; } + + return 0; } static void io_destroyer(void *p) { + dTHX; struct cbdata *cbd = p; SvREFCNT_dec(cbd->writecb); @@ -521,13 +553,13 @@ static struct value_name make_color_names[] = { "webmap", mc_web_map, }, { "addi", mc_addi, }, { "mediancut", mc_median_cut, }, + { "mono", mc_mono, }, + { "monochrome", mc_mono, }, }; static struct value_name translate_names[] = { -#ifdef HAVE_LIBGIF { "giflib", pt_giflib, }, -#endif { "closest", pt_closest, }, { "perturb", pt_perturb, }, { "errdiff", pt_errdiff, }, @@ -557,7 +589,8 @@ static struct value_name orddith_names[] = }; /* look through the hash for quantization options */ -static void handle_quant_opts(i_quantize *quant, HV *hv) +static void +ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) { /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/ SV **sv; @@ -608,7 +641,7 @@ static void handle_quant_opts(i_quantize *quant, HV *hv) } } } - quant->make_colors = mc_addi; + quant->make_colors = mc_median_cut; sv = hv_fetch(hv, "make_colors", 11, 0); if (sv && *sv && (str = SvPV(*sv, len))) { quant->make_colors = @@ -688,14 +721,16 @@ static void handle_quant_opts(i_quantize *quant, HV *hv) quant->perturb = SvIV(*sv); } -static void cleanup_quant_opts(i_quantize *quant) { +static void +ip_cleanup_quant_opts(pTHX_ i_quantize *quant) { myfree(quant->mc_colors); if (quant->ed_map) myfree(quant->ed_map); } /* copies the color map from the hv into the colors member of the HV */ -static void copy_colors_back(HV *hv, i_quantize *quant) { +static void +ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) { SV **sv; AV *av; int i; @@ -703,14 +738,12 @@ static void copy_colors_back(HV *hv, i_quantize *quant) { sv = hv_fetch(hv, "colors", 6, 0); if (!sv || !*sv || !SvROK(*sv) || SvTYPE(SvRV(*sv)) != SVt_PVAV) { - SV *ref; - av = newAV(); - ref = newRV_inc((SV*) av); - sv = hv_store(hv, "colors", 6, ref, 0); - } - else { - av = (AV *)SvRV(*sv); + /* nothing to do */ + return; } + + av = (AV *)SvRV(*sv); + av_clear(av); av_extend(av, quant->mc_count+1); for (i = 0; i < quant->mc_count; ++i) { i_color *in = quant->mc_colors+i; @@ -718,15 +751,13 @@ static void copy_colors_back(HV *hv, i_quantize *quant) { work = sv_newmortal(); sv_setref_pv(work, "Imager::Color", (void *)c); SvREFCNT_inc(work); - if (!av_store(av, i, work)) { - SvREFCNT_dec(work); - } + av_push(av, work); } } /* loads the segments of a fountain fill into an array */ static i_fountain_seg * -load_fount_segs(AV *asegs, int *count) { +load_fount_segs(pTHX_ AV *asegs, int *count) { /* Each element of segs must contain: [ start, middle, end, c0, c1, segtype, colortrans ] start, middle, end are doubles from 0 to 1 @@ -800,6 +831,29 @@ load_fount_segs(AV *asegs, int *count) { return segs; } +/* validates the indexes supplied to i_ppal + +i_ppal() doesn't do that for speed, but I'm not comfortable doing that +for calls from perl. + +*/ +static void +validate_i_ppal(i_img *im, i_palidx const *indexes, int count) { + int color_count = i_colorcount(im); + int i; + + if (color_count == -1) + croak("i_plin() called on direct color image"); + + for (i = 0; i < count; ++i) { + if (indexes[i] >= color_count) { + croak("i_plin() called with out of range color index %d (max %d)", + indexes[i], color_count-1); + } + } +} + + /* 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 @@ -838,6 +892,8 @@ i_int_hlines_DESTROY(i_int_hlines *hlines) { myfree(hlines); } +#define i_int_hlines_CLONE_SKIP(cls) 1 + static int seg_compare(const void *vleft, const void *vright) { const i_int_hline_seg *left = vleft; const i_int_hline_seg *right = vright; @@ -847,6 +903,7 @@ static int seg_compare(const void *vleft, const void *vright) { static SV * i_int_hlines_dump(i_int_hlines *hlines) { + dTHX; SV *dump = newSVpvf("start_y: %d limit_y: %d start_x: %d limit_x: %d\n", hlines->start_y, hlines->limit_y, hlines->start_x, hlines->limit_x); int y; @@ -873,12 +930,30 @@ i_int_hlines_dump(i_int_hlines *hlines) { #endif +static im_pl_ext_funcs im_perl_funcs = +{ + IMAGER_PL_API_VERSION, + IMAGER_PL_API_LEVEL, + ip_handle_quant_opts, + ip_cleanup_quant_opts, + ip_copy_colors_back +}; + +#define PERL_PL_SET_GLOBAL_CALLBACKS \ + sv_setiv(get_sv(PERL_PL_FUNCTION_TABLE_NAME, 1), PTR2IV(&im_perl_funcs)); + #ifdef IMEXIF_ENABLE #define i_exif_enabled() 1 #else #define i_exif_enabled() 0 #endif +/* trying to use more C style names, map them here */ +#define i_io_DESTROY(ig) io_glue_destroy(ig) + +#define i_img_get_width(im) ((im)->xsize) +#define i_img_get_height(im) ((im)->ysize) + MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_ Imager::Color @@ -1101,19 +1176,111 @@ i_get_image_file_limits() PUSHs(sv_2mortal(newSViv(bytes))); } -MODULE = Imager PACKAGE = Imager::IO PREFIX = io_glue_ +MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_ + +int +i_io_write(ig, data_sv) + Imager::IO ig + SV *data_sv + PREINIT: + 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); + RETVAL = i_io_write(ig, data, size); + OUTPUT: + RETVAL + +void +i_io_read(ig, buffer_sv, size) + Imager::IO ig + SV *buffer_sv + int size + PREINIT: + void *buffer; + int result; + PPCODE: + if (size <= 0) + croak("size negative in call to i_io_read()"); + /* prevent an undefined value warning if they supplied an + undef buffer. + Orginally conditional on !SvOK(), but this will prevent the + downgrade from croaking */ + sv_setpvn(buffer_sv, "", 0); +#ifdef SvUTF8 + if (SvUTF8(buffer_sv)) + sv_utf8_downgrade(buffer_sv, FALSE); +#endif + buffer = SvGROW(buffer_sv, size+1); + result = i_io_read(ig, buffer, size); + if (result >= 0) { + SvCUR_set(buffer_sv, result); + *SvEND(buffer_sv) = '\0'; + SvPOK_only(buffer_sv); + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSViv(result))); + } + ST(1) = buffer_sv; + SvSETMAGIC(ST(1)); + +void +i_io_read2(ig, size) + Imager::IO ig + int size + PREINIT: + SV *buffer_sv; + void *buffer; + int result; + PPCODE: + if (size <= 0) + croak("size negative in call to i_io_read2()"); + buffer_sv = newSV(size); + buffer = SvGROW(buffer_sv, size+1); + result = i_io_read(ig, buffer, size); + if (result >= 0) { + SvCUR_set(buffer_sv, result); + *SvEND(buffer_sv) = '\0'; + SvPOK_only(buffer_sv); + EXTEND(SP, 1); + PUSHs(sv_2mortal(buffer_sv)); + } + else { + /* discard it */ + SvREFCNT_dec(buffer_sv); + } + +int +i_io_seek(ig, position, whence) + Imager::IO ig + long position + int whence + +int +i_io_close(ig) + Imager::IO ig void -io_glue_DESTROY(ig) +i_io_DESTROY(ig) Imager::IO ig +int +i_io_CLONE_SKIP(...) + CODE: + RETVAL = 1; + OUTPUT: + RETVAL MODULE = Imager PACKAGE = Imager PROTOTYPES: ENABLE - - void i_list_formats() PREINIT: @@ -1160,12 +1327,16 @@ i_sametype_chans(im, x, y, channels) int channels void -m_init_log(name,level) - char* name +i_init_log(name_sv,level) + SV* name_sv int level + PREINIT: + const char *name = SvOK(name_sv) ? SvPV_nolen(name_sv) : NULL; + CODE: + i_init_log(name, level); void -log_entry(string,level) +i_log_entry(string,level) char* string int level @@ -1216,6 +1387,34 @@ i_img_getdata(im) sv_2mortal(newSVpv((char *)im->idata, im->bytes)) : &PL_sv_undef); +IV +i_img_get_width(im) + Imager::ImgRaw im + +IV +i_img_get_height(im) + Imager::ImgRaw im + + +void +i_img_is_monochrome(im) + Imager::ImgRaw im + PREINIT: + int zero_is_white; + int result; + PPCODE: + result = i_img_is_monochrome(im, &zero_is_white); + if (result) { + if (GIMME_V == G_ARRAY) { + EXTEND(SP, 2); + PUSHs(&PL_sv_yes); + PUSHs(sv_2mortal(newSViv(zero_is_white))); + } + else { + EXTEND(SP, 1); + PUSHs(&PL_sv_yes); + } + } void i_line(im,x1,y1,x2,y2,val,endp) @@ -1313,6 +1512,41 @@ i_circle_aa(im,x,y,rad,val) float rad Imager::Color val +int +i_circle_out(im,x,y,rad,val) + Imager::ImgRaw im + i_img_dim x + i_img_dim y + i_img_dim rad + Imager::Color val + +int +i_circle_out_aa(im,x,y,rad,val) + Imager::ImgRaw im + i_img_dim x + i_img_dim y + i_img_dim rad + Imager::Color val + +int +i_arc_out(im,x,y,rad,d1,d2,val) + Imager::ImgRaw im + i_img_dim x + i_img_dim y + i_img_dim rad + float d1 + float d2 + Imager::Color val + +int +i_arc_out_aa(im,x,y,rad,d1,d2,val) + Imager::ImgRaw im + i_img_dim x + i_img_dim y + i_img_dim rad + float d1 + float d2 + Imager::Color val void @@ -1350,7 +1584,7 @@ i_bezier_multi(im,xc,yc,val) myfree(y); -void +int i_poly_aa(im,xc,yc,val) Imager::ImgRaw im Imager::Color val @@ -1362,7 +1596,7 @@ i_poly_aa(im,xc,yc,val) SV *sv1; SV *sv2; int i; - PPCODE: + CODE: ICL_info(val); if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n"); if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa must be a reference to an array\n"); @@ -1380,11 +1614,13 @@ i_poly_aa(im,xc,yc,val) x[i]=(double)SvNV(sv1); y[i]=(double)SvNV(sv2); } - i_poly_aa(im,len,x,y,val); + RETVAL = i_poly_aa(im,len,x,y,val); myfree(x); myfree(y); + OUTPUT: + RETVAL -void +int i_poly_aa_cfill(im,xc,yc,fill) Imager::ImgRaw im Imager::FillHandle fill @@ -1396,7 +1632,7 @@ i_poly_aa_cfill(im,xc,yc,fill) SV *sv1; SV *sv2; int i; - PPCODE: + CODE: if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n"); if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n"); if (!SvROK(ST(2))) croak("Imager: Parameter 1 to i_poly_aa_cfill must be a reference to an array\n"); @@ -1413,9 +1649,11 @@ i_poly_aa_cfill(im,xc,yc,fill) x[i]=(double)SvNV(sv1); y[i]=(double)SvNV(sv2); } - i_poly_aa_cfill(im,len,x,y,fill); + RETVAL = i_poly_aa_cfill(im,len,x,y,fill); myfree(x); myfree(y); + OUTPUT: + RETVAL @@ -1433,6 +1671,22 @@ i_flood_cfill(im,seedx,seedy,fill) int seedy Imager::FillHandle fill +undef_int +i_flood_fill_border(im,seedx,seedy,dcol, border) + Imager::ImgRaw im + int seedx + int seedy + Imager::Color dcol + Imager::Color border + +undef_int +i_flood_cfill_border(im,seedx,seedy,fill, border) + Imager::ImgRaw im + int seedx + int seedy + Imager::FillHandle fill + Imager::Color border + void i_copyto(im,src,x1,y1,x2,y2,tx,ty) @@ -1474,6 +1728,75 @@ i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy) int src_maxx int src_maxy +undef_int +i_compose(out, src, out_left, out_top, src_left, src_top, width, height, combine = ic_normal, opacity = 0.0) + Imager::ImgRaw out + Imager::ImgRaw src + int out_left + int out_top + int src_left + int src_top + int width + int height + int combine + double opacity + +undef_int +i_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) + Imager::ImgRaw out + Imager::ImgRaw src + Imager::ImgRaw mask + int out_left + int out_top + int src_left + int src_top + int mask_left + int mask_top + int width + int height + int combine + double opacity + +Imager::ImgRaw +i_combine(src_av, channels_av = NULL) + AV *src_av + AV *channels_av + PREINIT: + i_img **imgs = NULL; + STRLEN in_count; + int *channels = NULL; + int i; + SV **psv; + IV tmp; + CODE: + in_count = av_len(src_av) + 1; + if (in_count > 0) { + imgs = mymalloc(sizeof(i_img*) * in_count); + channels = mymalloc(sizeof(int) * in_count); + for (i = 0; i < in_count; ++i) { + psv = av_fetch(src_av, i, 0); + if (!psv || !*psv || !sv_derived_from(*psv, "Imager::ImgRaw")) { + myfree(imgs); + myfree(channels); + croak("imgs must contain only images"); + } + tmp = SvIV((SV*)SvRV(*psv)); + imgs[i] = INT2PTR(i_img*, tmp); + if (channels_av && + (psv = av_fetch(channels_av, i, 0)) != NULL && + *psv) { + channels[i] = SvIV(*psv); + } + else { + channels[i] = 0; + } + } + } + RETVAL = i_combine(imgs, channels, in_count); + myfree(imgs); + myfree(channels); + OUTPUT: + RETVAL undef_int i_flipxy(im, direction) @@ -1555,10 +1878,10 @@ i_matrix_transform(im, xsize, ysize, matrix, ...) OUTPUT: RETVAL -void +undef_int i_gaussian(im,stdev) Imager::ImgRaw im - float stdev + double stdev void i_unsharp_mask(im,stdev,scale) @@ -1566,45 +1889,40 @@ i_unsharp_mask(im,stdev,scale) float stdev double scale -void -i_conv(im,pcoef) - Imager::ImgRaw im - PREINIT: - float* coeff; - int len; - AV* av; - SV* sv1; - int i; - PPCODE: - if (!SvROK(ST(1))) croak("Imager: Parameter 1 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"); - av=(AV*)SvRV(ST(1)); - len=av_len(av)+1; - coeff=mymalloc( len*sizeof(float) ); - for(i=0;ifunction_list[i].name != NULL) { + while( functions[i].name != NULL) { EXTEND(SP,1); - PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i].name,0))); + PUSHs(sv_2mortal(newSVpv(functions[i].name,0))); EXTEND(SP,1); - PUSHs(sv_2mortal(newSVpv(dso_handle->function_list[i++].pcode,0))); + PUSHs(sv_2mortal(newSVpv(functions[i++].pcode,0))); } - void DSO_call(handle,func_index,hv) void* handle @@ -3308,8 +3016,6 @@ DSO_call(handle,func_index,hv) if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 2 must be a reference to a hash\n"); DSO_call( (DSO_handle *)handle,func_index,hv); - - SV * i_get_pixel(im, x, y) Imager::ImgRaw im @@ -3356,13 +3062,14 @@ i_img_to_pal(src, quant) croak("i_img_to_pal: second argument must be a hash ref"); hv = (HV *)SvRV(ST(1)); memset(&quant, 0, sizeof(quant)); + quant.version = 1; quant.mc_size = 256; - handle_quant_opts(&quant, hv); + ip_handle_quant_opts(aTHX_ &quant, hv); RETVAL = i_img_to_pal(src, &quant); if (RETVAL) { - copy_colors_back(hv, &quant); + ip_copy_colors_back(aTHX_ hv, &quant); } - cleanup_quant_opts(&quant); + ip_cleanup_quant_opts(aTHX_ &quant); OUTPUT: RETVAL @@ -3416,6 +3123,7 @@ i_ppal(im, l, y, ...) for (i=0; i < items-3; ++i) { work[i] = SvIV(ST(i+3)); } + validate_i_ppal(im, work, items - 3); RETVAL = i_ppal(im, l, l+items-3, y, work); myfree(work); } @@ -3425,6 +3133,28 @@ i_ppal(im, l, y, ...) OUTPUT: RETVAL +int +i_ppal_p(im, l, y, data) + Imager::ImgRaw im + int l + int y + SV *data + PREINIT: + i_palidx const *work; + STRLEN len; + CODE: + work = (i_palidx const *)SvPV(data, len); + len /= sizeof(i_palidx); + if (len > 0) { + validate_i_ppal(im, work, len); + RETVAL = i_ppal(im, l, l+len, y, work); + } + else { + RETVAL = 0; + } + OUTPUT: + RETVAL + SV * i_addcolors(im, ...) Imager::ImgRaw im @@ -3593,6 +3323,108 @@ i_gsamp(im, l, r, y, ...) } } +undef_neg_int +i_gsamp_bits(im, l, r, y, bits, target, offset, ...) + Imager::ImgRaw im + int l + int r + int y + int bits + AV *target + int offset + PREINIT: + int *chans; + int chan_count; + unsigned *data; + int count, i; + CODE: + i_clear_error(); + if (items < 8) + croak("No channel numbers supplied to g_samp()"); + if (l < r) { + chan_count = items - 7; + chans = mymalloc(sizeof(int) * chan_count); + for (i = 0; i < chan_count; ++i) + chans[i] = SvIV(ST(i+7)); + data = mymalloc(sizeof(unsigned) * (r-l) * chan_count); + count = i_gsamp_bits(im, l, r, y, data, chans, chan_count, bits); + myfree(chans); + for (i = 0; i < count; ++i) { + av_store(target, i+offset, newSVuv(data[i])); + } + myfree(data); + RETVAL = count; + } + else { + RETVAL = 0; + } + OUTPUT: + RETVAL + +undef_neg_int +i_psamp_bits(im, l, y, bits, channels_sv, data_av, data_offset = 0, pixel_count = -1) + Imager::ImgRaw im + int l + int y + int bits + SV *channels_sv + AV *data_av + int data_offset + int pixel_count + PREINIT: + int chan_count; + int *channels; + int data_count; + int data_used; + unsigned *data; + int i; + CODE: + i_clear_error(); + if (SvOK(channels_sv)) { + AV *channels_av; + if (!SvROK(channels_sv) || SvTYPE(SvRV(channels_sv)) != SVt_PVAV) { + croak("channels is not an array ref"); + } + channels_av = (AV *)SvRV(channels_sv); + chan_count = av_len(channels_av) + 1; + if (chan_count < 1) { + croak("i_psamp_bits: no channels provided"); + } + channels = mymalloc(sizeof(int) * chan_count); + for (i = 0; i < chan_count; ++i) + channels[i] = SvIV(*av_fetch(channels_av, i, 0)); + } + else { + chan_count = im->channels; + channels = NULL; + } + + data_count = av_len(data_av) + 1; + if (data_offset < 0) { + croak("data_offset must by non-negative"); + } + if (data_offset > data_count) { + croak("data_offset greater than number of samples supplied"); + } + if (pixel_count == -1 || + data_offset + pixel_count * chan_count > data_count) { + pixel_count = (data_count - data_offset) / chan_count; + } + + data_used = pixel_count * chan_count; + data = mymalloc(sizeof(unsigned) * data_count); + for (i = 0; i < data_used; ++i) + data[i] = SvUV(*av_fetch(data_av, data_offset + i, 0)); + + RETVAL = i_psamp_bits(im, l, l + pixel_count, y, data, channels, + chan_count, bits); + + if (data) + myfree(data); + if (channels) + myfree(channels); + OUTPUT: + RETVAL Imager::ImgRaw i_img_masked_new(targ, mask, x, y, w, h) @@ -3785,6 +3617,7 @@ i_glin(im, l, r, y) PPCODE: if (l < r) { vals = mymalloc((r-l) * sizeof(i_color)); + memset(vals, 0, (r-l) * sizeof(i_color)); count = i_glin(im, l, r, y, vals); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); @@ -3813,9 +3646,14 @@ i_glinf(im, l, r, y) PREINIT: i_fcolor *vals; int count, i; + i_fcolor zero; PPCODE: + for (i = 0; i < MAXCHANNELS; ++i) + zero.channel[i] = 0; if (l < r) { vals = mymalloc((r-l) * sizeof(i_fcolor)); + for (i = 0; i < r-l; ++i) + vals[i] = zero; count = i_glinf(im, l, r, y, vals); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); @@ -3841,6 +3679,10 @@ i_img_16_new(x, y, ch) int y int ch +Imager::ImgRaw +i_img_to_rgb16(im) + Imager::ImgRaw im + Imager::ImgRaw i_img_double_new(x, y, ch) int x @@ -4007,396 +3849,7 @@ i_tags_count(im) OUTPUT: RETVAL -#ifdef HAVE_WIN32 - -void -i_wf_bbox(face, size, text) - char *face - int size - char *text - PREINIT: - int cords[BOUNDING_BOX_COUNT]; - int rc, i; - PPCODE: - if (rc = i_wf_bbox(face, size, text, strlen(text), cords)) { - EXTEND(SP, rc); - for (i = 0; i < rc; ++i) - PUSHs(sv_2mortal(newSViv(cords[i]))); - } - -undef_int -i_wf_text(face, im, tx, ty, cl, size, text, align, aa) - char *face - Imager::ImgRaw im - int tx - int ty - Imager::Color cl - int size - char *text - int align - int aa - CODE: - RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), - align, aa); - OUTPUT: - RETVAL - -undef_int -i_wf_cp(face, im, tx, ty, channel, size, text, align, aa) - char *face - Imager::ImgRaw im - int tx - int ty - int channel - int size - char *text - int align - int aa - CODE: - RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), - align, aa); - OUTPUT: - RETVAL - -undef_int -i_wf_addfont(font) - char *font - -#endif - -#ifdef HAVE_FT2 - -MODULE = Imager PACKAGE = Imager::Font::FT2 PREFIX=FT2_ - -#define FT2_DESTROY(font) i_ft2_destroy(font) - -void -FT2_DESTROY(font) - Imager::Font::FT2 font - -MODULE = Imager PACKAGE = Imager::Font::FreeType2 - -Imager::Font::FT2 -i_ft2_new(name, index) - char *name - int index - -undef_int -i_ft2_setdpi(font, xdpi, ydpi) - Imager::Font::FT2 font - int xdpi - int ydpi - -void -i_ft2_getdpi(font) - Imager::Font::FT2 font - PREINIT: - int xdpi, ydpi; - CODE: - if (i_ft2_getdpi(font, &xdpi, &ydpi)) { - EXTEND(SP, 2); - PUSHs(sv_2mortal(newSViv(xdpi))); - PUSHs(sv_2mortal(newSViv(ydpi))); - } - -undef_int -i_ft2_sethinting(font, hinting) - Imager::Font::FT2 font - int hinting - -undef_int -i_ft2_settransform(font, matrix) - Imager::Font::FT2 font - PREINIT: - double matrix[6]; - int len; - AV *av; - SV *sv1; - int i; - CODE: - if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV) - croak("i_ft2_settransform: parameter 2 must be an array ref\n"); - av=(AV*)SvRV(ST(1)); - len=av_len(av)+1; - if (len > 6) - len = 6; - for (i = 0; i < len; ++i) { - sv1=(*(av_fetch(av,i,0))); - matrix[i] = SvNV(sv1); - } - for (; i < 6; ++i) - matrix[i] = 0; - RETVAL = i_ft2_settransform(font, matrix); - OUTPUT: - RETVAL - -void -i_ft2_bbox(font, cheight, cwidth, text_sv, utf8) - Imager::Font::FT2 font - double cheight - double cwidth - SV *text_sv - int utf8 - PREINIT: - int bbox[BOUNDING_BOX_COUNT]; - int i; - char *text; - STRLEN text_len; - int rc; - PPCODE: - text = SvPV(text_sv, text_len); -#ifdef SvUTF8 - if (SvUTF8(text_sv)) - utf8 = 1; -#endif - rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8); - if (rc) { - EXTEND(SP, rc); - for (i = 0; i < rc; ++i) - PUSHs(sv_2mortal(newSViv(bbox[i]))); - } - -void -i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8) - Imager::Font::FT2 font - double cheight - double cwidth - char *text - int vlayout - int utf8 - PREINIT: - int bbox[8]; - int i; - PPCODE: -#ifdef SvUTF8 - if (SvUTF8(ST(3))) - utf8 = 1; -#endif - if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout, - utf8, bbox)) { - EXTEND(SP, 8); - for (i = 0; i < 8; ++i) - PUSHs(sv_2mortal(newSViv(bbox[i]))); - } - -undef_int -i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8) - Imager::Font::FT2 font - Imager::ImgRaw im - int tx - int ty - Imager::Color cl - double cheight - double cwidth - int align - int aa - int vlayout - int utf8 - PREINIT: - char *text; - STRLEN len; - CODE: -#ifdef SvUTF8 - if (SvUTF8(ST(7))) { - utf8 = 1; - } -#endif - text = SvPV(ST(7), len); - RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, - len, align, aa, vlayout, utf8); - OUTPUT: - RETVAL - -undef_int -i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8) - Imager::Font::FT2 font - Imager::ImgRaw im - int tx - int ty - int channel - double cheight - double cwidth - char *text - int align - int aa - int vlayout - int utf8 - CODE: -#ifdef SvUTF8 - if (SvUTF8(ST(7))) - utf8 = 1; -#endif - RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, - strlen(text), align, aa, vlayout, 1); - OUTPUT: - RETVAL - -void -ft2_transform_box(font, x0, x1, x2, x3) - Imager::Font::FT2 font - int x0 - int x1 - int x2 - int x3 - PREINIT: - int box[4]; - PPCODE: - box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3; - ft2_transform_box(font, box); - EXTEND(SP, 4); - PUSHs(sv_2mortal(newSViv(box[0]))); - PUSHs(sv_2mortal(newSViv(box[1]))); - PUSHs(sv_2mortal(newSViv(box[2]))); - PUSHs(sv_2mortal(newSViv(box[3]))); - -void -i_ft2_has_chars(handle, text_sv, utf8) - Imager::Font::FT2 handle - SV *text_sv - int utf8 - PREINIT: - char *text; - STRLEN len; - char *work; - int count; - int i; - PPCODE: -#ifdef SvUTF8 - if (SvUTF8(text_sv)) - utf8 = 1; -#endif - text = SvPV(text_sv, len); - work = mymalloc(len); - count = i_ft2_has_chars(handle, text, len, utf8, work); - if (GIMME_V == G_ARRAY) { - EXTEND(SP, count); - for (i = 0; i < count; ++i) { - PUSHs(sv_2mortal(newSViv(work[i]))); - } - } - else { - EXTEND(SP, 1); - PUSHs(sv_2mortal(newSVpv(work, count))); - } - myfree(work); - -void -i_ft2_face_name(handle) - Imager::Font::FT2 handle - PREINIT: - char name[255]; - int len; - PPCODE: - len = i_ft2_face_name(handle, name, sizeof(name)); - if (len) { - EXTEND(SP, 1); - PUSHs(sv_2mortal(newSVpv(name, 0))); - } - -undef_int -i_ft2_can_face_name() - -void -i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1) - Imager::Font::FT2 handle - SV *text_sv - int utf8 - int reliable_only - PREINIT: - char const *text; - STRLEN work_len; - int len; - char name[255]; - PPCODE: -#ifdef SvUTF8 - if (SvUTF8(text_sv)) - utf8 = 1; -#endif - text = SvPV(text_sv, work_len); - len = work_len; - while (len) { - unsigned long ch; - if (utf8) { - ch = i_utf8_advance(&text, &len); - if (ch == ~0UL) { - i_push_error(0, "invalid UTF8 character"); - break; - } - } - else { - ch = *text++; - --len; - } - EXTEND(SP, 1); - if (i_ft2_glyph_name(handle, ch, name, sizeof(name), - reliable_only)) { - PUSHs(sv_2mortal(newSVpv(name, 0))); - } - else { - PUSHs(&PL_sv_undef); - } - } - -int -i_ft2_can_do_glyph_names() - -int -i_ft2_face_has_glyph_names(handle) - Imager::Font::FT2 handle - -int -i_ft2_is_multiple_master(handle) - Imager::Font::FT2 handle - -void -i_ft2_get_multiple_masters(handle) - Imager::Font::FT2 handle - PREINIT: - i_font_mm mm; - int i; - PPCODE: - if (i_ft2_get_multiple_masters(handle, &mm)) { - EXTEND(SP, 2+mm.num_axis); - PUSHs(sv_2mortal(newSViv(mm.num_axis))); - PUSHs(sv_2mortal(newSViv(mm.num_designs))); - for (i = 0; i < mm.num_axis; ++i) { - AV *av = newAV(); - SV *sv; - av_extend(av, 3); - sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name)); - SvREFCNT_inc(sv); - av_store(av, 0, sv); - sv = newSViv(mm.axis[i].minimum); - SvREFCNT_inc(sv); - av_store(av, 1, sv); - sv = newSViv(mm.axis[i].maximum); - SvREFCNT_inc(sv); - av_store(av, 2, sv); - PUSHs(newRV_noinc((SV *)av)); - } - } - -undef_int -i_ft2_set_mm_coords(handle, ...) - Imager::Font::FT2 handle - PROTOTYPE: DISABLE - PREINIT: - long *coords; - int ix_coords, i; - CODE: - /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so - transfer the array manually */ - ix_coords = items-1; - coords = mymalloc(sizeof(long) * ix_coords); - for (i = 0; i < ix_coords; ++i) { - coords[i] = (long)SvIV(ST(1+i)); - } - RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords); - myfree(coords); - OUTPUT: - RETVAL -#endif MODULE = Imager PACKAGE = Imager::FillHandle PREFIX=IFILL_ @@ -4404,6 +3857,13 @@ void IFILL_DESTROY(fill) Imager::FillHandle fill +int +IFILL_CLONE_SKIP(...) + CODE: + RETVAL = 1; + OUTPUT: + RETVAL + MODULE = Imager PACKAGE = Imager Imager::FillHandle @@ -4529,7 +3989,12 @@ SV * i_int_hlines_dump(hlines) Imager::Internal::Hlines hlines +int +i_int_hlines_CLONE_SKIP(cls) + SV *cls + #endif BOOT: PERL_SET_GLOBAL_CALLBACKS; + PERL_PL_SET_GLOBAL_CALLBACKS; \ No newline at end of file