X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/77157728e2173c7fc0bc905fc4b3db5df6669e96..b47464c19c81e26fb5c8086d66f05c012a6c36cc:/Imager.xs diff --git a/Imager.xs b/Imager.xs index 43ea0d85..4a82c12f 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1,35 +1,35 @@ +#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 - +} #endif -#include "image.h" +#define i_int_hlines_testing() 1 + +#include "imager.h" #include "feat.h" #include "dynaload.h" #include "regmach.h" +#include "imextdef.h" +#include "imextpltypes.h" -typedef io_glue* Imager__IO; -typedef i_color* Imager__Color; -typedef i_fcolor* Imager__Color__Float; -typedef i_img* Imager__ImgRaw; -typedef int undef_neg_int; - -#ifdef HAVE_LIBTT -typedef TT_Fonthandle* Imager__Font__TT; +#if i_int_hlines_testing() +#include "imageri.h" #endif -#ifdef HAVE_FT2 -typedef FT2_Fonthandle* Imager__Font__FT2; -#endif +#include "imperl.h" /* 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; @@ -44,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; @@ -57,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; @@ -69,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; @@ -83,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; @@ -106,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)); } @@ -124,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; @@ -175,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; @@ -246,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; @@ -275,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; @@ -326,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; @@ -378,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; } @@ -395,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; } @@ -409,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; @@ -433,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, @@ -448,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*/ @@ -457,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; } @@ -485,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); @@ -524,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, }, @@ -560,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; @@ -691,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; @@ -706,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; @@ -721,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 @@ -803,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 @@ -810,17 +861,99 @@ load_fount_segs(AV *asegs, int *count) { #define ICLF_new_internal(r, g, b, a) i_fcolor_new((r), (g), (b), (a)) #define ICLF_DESTROY(cl) i_fcolor_destroy(cl) -/* for the fill objects - Since a fill object may later have dependent images, (or fills!) - we need perl wrappers - oh well -*/ -#define IFILL_DESTROY(fill) i_fill_destroy(fill); -typedef i_fill_t* Imager__FillHandle; /* the m_init_log() function was called init_log(), renamed to reduce potential naming conflicts */ #define init_log m_init_log +#if i_int_hlines_testing() + +typedef i_int_hlines *Imager__Internal__Hlines; + +static i_int_hlines * +i_int_hlines_new(int start_y, int count_y, int start_x, int count_x) { + i_int_hlines *result = mymalloc(sizeof(i_int_hlines)); + i_int_init_hlines(result, start_y, count_y, start_x, count_x); + + return result; +} + +static i_int_hlines * +i_int_hlines_new_img(i_img *im) { + i_int_hlines *result = mymalloc(sizeof(i_int_hlines)); + i_int_init_hlines_img(result, im); + + return result; +} + +static void +i_int_hlines_DESTROY(i_int_hlines *hlines) { + i_int_hlines_destroy(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; + + return left->minx - right->minx; +} + +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; + + for (y = hlines->start_y; y < hlines->limit_y; ++y) { + i_int_hline_entry *entry = hlines->entries[y-hlines->start_y]; + if (entry) { + int i; + /* sort the segments, if any */ + if (entry->count) + qsort(entry->segs, entry->count, sizeof(i_int_hline_seg), seg_compare); + + sv_catpvf(dump, " %d (%d):", y, entry->count); + for (i = 0; i < entry->count; ++i) { + sv_catpvf(dump, " [%d, %d)", entry->segs[i].minx, + entry->segs[i].x_limit); + } + sv_catpv(dump, "\n"); + } + } + + return dump; +} + +#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 @@ -1043,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: @@ -1102,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 @@ -1158,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) @@ -1216,6 +1473,16 @@ i_arc(im,x,y,rad,d1,d2,val) float 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 + Imager::Color val + void i_arc_cfill(im,x,y,rad,d1,d2,fill) Imager::ImgRaw im @@ -1226,6 +1493,15 @@ i_arc_cfill(im,x,y,rad,d1,d2,fill) float 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 + Imager::FillHandle fill void @@ -1236,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 @@ -1273,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 @@ -1285,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"); @@ -1303,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 @@ -1319,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"); @@ -1336,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 @@ -1356,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) @@ -1381,9 +1712,8 @@ i_copyto_trans(im,src,x1,y1,x2,y2,tx,ty,trans) int ty Imager::Color trans -void -i_copy(im,src) - Imager::ImgRaw im +Imager::ImgRaw +i_copy(src) Imager::ImgRaw src @@ -1398,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) @@ -1479,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) @@ -1490,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 @@ -3239,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 @@ -3287,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 @@ -3347,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); } @@ -3356,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 @@ -3375,7 +3174,7 @@ i_addcolors(im, ...) } else { myfree(colors); - croak("i_plin: pixels must be Imager::Color objects"); + croak("i_addcolor: pixels must be Imager::Color objects"); } } index = i_addcolors(im, colors, items-1); @@ -3524,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) @@ -3556,23 +3457,35 @@ i_plin(im, l, y, ...) PREINIT: i_color *work; int i; + STRLEN len; + int count; CODE: if (items > 3) { - work = mymalloc(sizeof(i_color) * (items-3)); - for (i=0; i < items-3; ++i) { - if (sv_isobject(ST(i+3)) - && sv_derived_from(ST(i+3), "Imager::Color")) { - IV tmp = SvIV((SV *)SvRV(ST(i+3))); - work[i] = *INT2PTR(i_color *, tmp); + if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) { + /* supplied as a byte string */ + work = (i_color *)SvPV(ST(3), len); + count = len / sizeof(i_color); + if (count * sizeof(i_color) != len) { + croak("i_plin: length of scalar argument must be multiple of sizeof i_color"); } - else { - myfree(work); - croak("i_plin: pixels must be Imager::Color objects"); + RETVAL = i_plin(im, l, l+count, y, work); + } + else { + work = mymalloc(sizeof(i_color) * (items-3)); + for (i=0; i < items-3; ++i) { + if (sv_isobject(ST(i+3)) + && sv_derived_from(ST(i+3), "Imager::Color")) { + IV tmp = SvIV((SV *)SvRV(ST(i+3))); + work[i] = *INT2PTR(i_color *, tmp); + } + else { + myfree(work); + croak("i_plin: pixels must be Imager::Color objects"); + } } + RETVAL = i_plin(im, l, l+items-3, y, work); + myfree(work); } - /**(char *)0 = 1;*/ - RETVAL = i_plin(im, l, l+items-3, y, work); - myfree(work); } else { RETVAL = 0; @@ -3608,6 +3521,7 @@ i_gsampf(im, l, r, y, ...) chans[i] = SvIV(ST(i+4)); data = mymalloc(sizeof(i_fsample_t) * (r-l) * chan_count); count = i_gsampf(im, l, r, y, data, chans, chan_count); + myfree(chans); if (GIMME_V == G_ARRAY) { EXTEND(SP, count); for (i = 0; i < count; ++i) @@ -3617,6 +3531,7 @@ i_gsampf(im, l, r, y, ...) EXTEND(SP, 1); PUSHs(sv_2mortal(newSVpv((void *)data, count * sizeof(i_fsample_t)))); } + myfree(data); } else { if (GIMME_V != G_ARRAY) { @@ -3633,23 +3548,36 @@ i_plinf(im, l, y, ...) PREINIT: i_fcolor *work; int i; + STRLEN len; + int count; CODE: if (items > 3) { - work = mymalloc(sizeof(i_fcolor) * (items-3)); - for (i=0; i < items-3; ++i) { - if (sv_isobject(ST(i+3)) - && sv_derived_from(ST(i+3), "Imager::Color::Float")) { - IV tmp = SvIV((SV *)SvRV(ST(i+3))); - work[i] = *INT2PTR(i_fcolor *, tmp); + if (items == 4 && SvOK(ST(3)) && !SvROK(ST(3))) { + /* supplied as a byte string */ + work = (i_fcolor *)SvPV(ST(3), len); + count = len / sizeof(i_fcolor); + if (count * sizeof(i_fcolor) != len) { + croak("i_plin: length of scalar argument must be multiple of sizeof i_fcolor"); } - else { - myfree(work); - croak("i_plin: pixels must be Imager::Color::Float objects"); + RETVAL = i_plinf(im, l, l+count, y, work); + } + else { + work = mymalloc(sizeof(i_fcolor) * (items-3)); + for (i=0; i < items-3; ++i) { + if (sv_isobject(ST(i+3)) + && sv_derived_from(ST(i+3), "Imager::Color::Float")) { + IV tmp = SvIV((SV *)SvRV(ST(i+3))); + work[i] = *INT2PTR(i_fcolor *, tmp); + } + else { + myfree(work); + croak("i_plinf: pixels must be Imager::Color::Float objects"); + } } + /**(char *)0 = 1;*/ + RETVAL = i_plinf(im, l, l+items-3, y, work); + myfree(work); } - /**(char *)0 = 1;*/ - RETVAL = i_plinf(im, l, l+items-3, y, work); - myfree(work); } else { RETVAL = 0; @@ -3689,15 +3617,22 @@ 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); - EXTEND(SP, count); - for (i = 0; i < count; ++i) { - SV *sv; - i_color *col = mymalloc(sizeof(i_color)); - *col = vals[i]; - sv = sv_newmortal(); - sv_setref_pv(sv, "Imager::Color", (void *)col); - PUSHs(sv); + if (GIMME_V == G_ARRAY) { + EXTEND(SP, count); + for (i = 0; i < count; ++i) { + SV *sv; + i_color *col = mymalloc(sizeof(i_color)); + *col = vals[i]; + sv = sv_newmortal(); + sv_setref_pv(sv, "Imager::Color", (void *)col); + PUSHs(sv); + } + } + else if (count) { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_color)))); } myfree(vals); } @@ -3711,18 +3646,29 @@ 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); - EXTEND(SP, count); - for (i = 0; i < count; ++i) { - SV *sv; - i_fcolor *col = mymalloc(sizeof(i_fcolor)); - *col = vals[i]; - sv = sv_newmortal(); - sv_setref_pv(sv, "Imager::Color::Float", (void *)col); - PUSHs(sv); + if (GIMME_V == G_ARRAY) { + EXTEND(SP, count); + for (i = 0; i < count; ++i) { + SV *sv; + i_fcolor *col = mymalloc(sizeof(i_fcolor)); + *col = vals[i]; + sv = sv_newmortal(); + sv_setref_pv(sv, "Imager::Color::Float", (void *)col); + PUSHs(sv); + } + } + else if (count) { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv((void *)vals, count * sizeof(i_fcolor)))); } myfree(vals); } @@ -3733,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 @@ -3899,397 +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; - int outsize; - 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 (outsize = 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_ @@ -4297,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 @@ -4387,3 +3954,47 @@ i_new_fill_image(src, matrix, xoff, yoff, combine) OUTPUT: RETVAL +MODULE = Imager PACKAGE = Imager::Internal::Hlines PREFIX=i_int_hlines_ + +# this class is only exposed for testing + +int +i_int_hlines_testing() + +#if i_int_hlines_testing() + +Imager::Internal::Hlines +i_int_hlines_new(start_y, count_y, start_x, count_x) + int start_y + int count_y + int start_x + int count_x + +Imager::Internal::Hlines +i_int_hlines_new_img(im) + Imager::ImgRaw im + +void +i_int_hlines_add(hlines, y, minx, width) + Imager::Internal::Hlines hlines + int y + int minx + int width + +void +i_int_hlines_DESTROY(hlines) + Imager::Internal::Hlines hlines + +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