X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/1bd75e4c20216e14c662bfb03308ebeb3c4b50a9..64ddd21f418352d0b77df9963cf7f7a0577d7c47:/Imager.xs diff --git a/Imager.xs b/Imager.xs index 2877f0f4..d2ea2cf7 100644 --- a/Imager.xs +++ b/Imager.xs @@ -4,39 +4,26 @@ extern "C" { #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" -typedef io_glue* Imager__IO; -typedef i_color* Imager__Color; -typedef i_fcolor* Imager__Color__Float; -typedef i_img* Imager__ImgRaw; - -/* later perls define this macro to prevent warning when converting -from IV to pointer types */ - -#ifndef INT2PTR -#define INT2PTR(type,value) (type)(value) -#endif - -#ifndef PTR2IV -#define PTR2IV(p) INT2PTR(IV,p) -#endif - -#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) { @@ -121,7 +108,7 @@ void my_SvREFCNT_dec(void *p) { static void -log_entry(char *string, int level) { +i_log_entry(char *string, int level) { mm_log((level, string)); } @@ -285,7 +272,7 @@ 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, @@ -338,9 +325,14 @@ static ssize_t call_reader(struct cbdata *cbd, void *buf, size_t size, static ssize_t write_flush(struct cbdata *cbd) { 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) { @@ -390,12 +382,11 @@ 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) { 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; } @@ -405,8 +396,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; } @@ -419,12 +411,13 @@ 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) { struct cbdata *cbd = p; ssize_t total; char *out = data; /* so we can do pointer arithmetic */ - int i; + /* printf("io_reader(%p, %p, %d)\n", p, data, size); */ if (cbd->writing) { if (write_flush(cbd) <= 0) return 0; @@ -444,7 +437,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, @@ -459,6 +452,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*/ @@ -468,16 +463,19 @@ 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) { struct cbdata *cbd = p; if (cbd->writing && cbd->used > 0) { - write_flush(cbd); + if (write_flush(cbd) < 0) + return -1; cbd->writing = 0; } @@ -496,6 +494,8 @@ static void io_closer(void *p) { FREETMPS; LEAVE; } + + return 0; } static void io_destroyer(void *p) { @@ -505,6 +505,7 @@ static void io_destroyer(void *p) { SvREFCNT_dec(cbd->readcb); SvREFCNT_dec(cbd->seekcb); SvREFCNT_dec(cbd->closecb); + myfree(cbd); } struct value_name { @@ -569,30 +570,6 @@ static struct value_name orddith_names[] = { "custom", od_custom, }, }; -static int -hv_fetch_bool(HV *hv, char *name, int def) { - SV **sv; - - sv = hv_fetch(hv, name, strlen(name), 0); - if (sv && *sv) { - return SvTRUE(*sv); - } - else - return def; -} - -static int -hv_fetch_int(HV *hv, char *name, int def) { - SV **sv; - - sv = hv_fetch(hv, name, strlen(name), 0); - if (sv && *sv) { - return SvIV(*sv); - } - else - return def; -} - /* look through the hash for quantization options */ static void handle_quant_opts(i_quantize *quant, HV *hv) { @@ -731,90 +708,6 @@ static void cleanup_quant_opts(i_quantize *quant) { myfree(quant->ed_map); } -#if 0 -/* look through the hash for options to add to opts */ -static void handle_gif_opts(i_gif_opts *opts, HV *hv) -{ - SV **sv; - int i; - /**((char *)0) = '\0';*/ - opts->each_palette = hv_fetch_bool(hv, "gif_each_palette", 0); - opts->interlace = hv_fetch_bool(hv, "interlace", 0); - - sv = hv_fetch(hv, "gif_delays", 10, 0); - if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { - AV *av = (AV*)SvRV(*sv); - opts->delay_count = av_len(av)+1; - opts->delays = mymalloc(sizeof(int) * opts->delay_count); - for (i = 0; i < opts->delay_count; ++i) { - SV *sv1 = *av_fetch(av, i, 0); - opts->delays[i] = SvIV(sv1); - } - } - sv = hv_fetch(hv, "gif_user_input", 14, 0); - if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { - AV *av = (AV*)SvRV(*sv); - opts->user_input_count = av_len(av)+1; - opts->user_input_flags = mymalloc(opts->user_input_count); - for (i = 0; i < opts->user_input_count; ++i) { - SV *sv1 = *av_fetch(av, i, 0); - opts->user_input_flags[i] = SvIV(sv1) != 0; - } - } - sv = hv_fetch(hv, "gif_disposal", 12, 0); - if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { - AV *av = (AV*)SvRV(*sv); - opts->disposal_count = av_len(av)+1; - opts->disposal = mymalloc(opts->disposal_count); - for (i = 0; i < opts->disposal_count; ++i) { - SV *sv1 = *av_fetch(av, i, 0); - opts->disposal[i] = SvIV(sv1); - } - } - sv = hv_fetch(hv, "gif_tran_color", 14, 0); - if (sv && *sv && SvROK(*sv) && sv_derived_from(*sv, "Imager::Color")) { - i_color *col = INT2PTR(i_color *, SvIV((SV *)SvRV(*sv))); - opts->tran_color = *col; - } - sv = hv_fetch(hv, "gif_positions", 13, 0); - if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { - AV *av = (AV *)SvRV(*sv); - opts->position_count = av_len(av) + 1; - opts->positions = mymalloc(sizeof(i_gif_pos) * opts->position_count); - for (i = 0; i < opts->position_count; ++i) { - SV **sv2 = av_fetch(av, i, 0); - opts->positions[i].x = opts->positions[i].y = 0; - if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) { - AV *av2 = (AV*)SvRV(*sv2); - SV **sv3; - sv3 = av_fetch(av2, 0, 0); - if (sv3 && *sv3) - opts->positions[i].x = SvIV(*sv3); - sv3 = av_fetch(av2, 1, 0); - if (sv3 && *sv3) - opts->positions[i].y = SvIV(*sv3); - } - } - } - /* Netscape2.0 loop count extension */ - opts->loop_count = hv_fetch_int(hv, "gif_loop_count", 0); - - opts->eliminate_unused = hv_fetch_bool(hv, "gif_eliminate_unused", 1); -} - -static void cleanup_gif_opts(i_gif_opts *opts) { - if (opts->delays) - myfree(opts->delays); - if (opts->user_input_flags) - myfree(opts->user_input_flags); - if (opts->disposal) - myfree(opts->disposal); - if (opts->positions) - myfree(opts->positions); -} - -#endif - /* copies the color map from the hv into the colors member of the HV */ static void copy_colors_back(HV *hv, i_quantize *quant) { SV **sv; @@ -856,7 +749,6 @@ load_fount_segs(AV *asegs, int *count) { */ int i, j; AV *aseg; - SV *sv; i_fountain_seg *segs; double work[3]; int worki[2]; @@ -922,6 +814,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 @@ -929,17 +844,81 @@ 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); +} + +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) { + 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 + +#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) + MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_ Imager::Color @@ -1062,7 +1041,6 @@ i_rgb_to_hsv(c) i_rgb_to_hsvf(RETVAL); OUTPUT: RETVAL - MODULE = Imager PACKAGE = Imager::ImgRaw PREFIX = IIM_ @@ -1096,7 +1074,6 @@ io_new_buffer(data) char *data PREINIT: size_t length; - SV* sv; CODE: SvPV(ST(0), length); SvREFCNT_inc(ST(0)); @@ -1146,18 +1123,121 @@ io_slurp(ig) myfree(data); -MODULE = Imager PACKAGE = Imager::IO PREFIX = io_glue_ +undef_int +i_set_image_file_limits(width, height, bytes) + int width + int height + int bytes void -io_glue_DESTROY(ig) - Imager::IO ig +i_get_image_file_limits() + PREINIT: + int width, height, bytes; + PPCODE: + if (i_get_image_file_limits(&width, &height, &bytes)) { + EXTEND(SP, 3); + PUSHs(sv_2mortal(newSViv(width))); + PUSHs(sv_2mortal(newSViv(height))); + PUSHs(sv_2mortal(newSViv(bytes))); + } +MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_ -MODULE = Imager PACKAGE = Imager +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 -PROTOTYPES: ENABLE +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 +i_io_DESTROY(ig) + Imager::IO ig + +MODULE = Imager PACKAGE = Imager +PROTOTYPES: ENABLE void i_list_formats() @@ -1191,13 +1271,26 @@ i_img_empty_ch(im,x,y,ch) int y int ch +Imager::ImgRaw +i_sametype(im, x, y) + Imager::ImgRaw im + int x + int y + +Imager::ImgRaw +i_sametype_chans(im, x, y, channels) + Imager::ImgRaw im + int x + int y + int channels + void -m_init_log(name,level) +i_init_log(name,level) char* name int level void -log_entry(string,level) +i_log_entry(string,level) char* string int level @@ -1306,6 +1399,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 @@ -1316,6 +1419,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 @@ -1446,6 +1558,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) @@ -1471,18 +1599,22 @@ 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 undef_int -i_rubthru(im,src,tx,ty) +i_rubthru(im,src,tx,ty,src_minx,src_miny,src_maxx,src_maxy) Imager::ImgRaw im Imager::ImgRaw src int tx int ty + int src_minx + int src_miny + int src_maxx + int src_maxy + undef_int i_flipxy(im, direction) @@ -1495,12 +1627,34 @@ i_rotate90(im, degrees) int degrees Imager::ImgRaw -i_rotate_exact(im, amount) +i_rotate_exact(im, amount, ...) Imager::ImgRaw im double amount + PREINIT: + i_color *backp = NULL; + i_fcolor *fbackp = NULL; + int i; + SV * sv1; + CODE: + /* extract the bg colors if any */ + /* yes, this is kind of strange */ + for (i = 2; 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_rotate_exact_bg(im, amount, backp, fbackp); + OUTPUT: + RETVAL Imager::ImgRaw -i_matrix_transform(im, xsize, ysize, matrix) +i_matrix_transform(im, xsize, ysize, matrix, ...) Imager::ImgRaw im int xsize int ysize @@ -1510,6 +1664,8 @@ i_matrix_transform(im, xsize, ysize, matrix) IV len; SV *sv1; int i; + i_color *backp = NULL; + i_fcolor *fbackp = NULL; CODE: if (!SvROK(ST(3)) || SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("i_matrix_transform: parameter 4 must be an array ref\n"); @@ -1523,7 +1679,20 @@ i_matrix_transform(im, xsize, ysize, matrix) } for (; i < 9; ++i) matrix[i] = 0; - RETVAL = i_matrix_transform(im, xsize, ysize, matrix); + /* 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 @@ -1570,7 +1739,6 @@ i_convert(im, src, coeff) int inchan; AV *avmain; SV **temp; - SV *svsub; AV *avsub; int len; int i, j; @@ -1715,18 +1883,21 @@ i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="") PREINIT: char *str; STRLEN len; - int cords[6]; + int cords[BOUNDING_BOX_COUNT]; int i; + int rc; PPCODE: #ifdef SvUTF8 if (SvUTF8(str_sv)) utf8 = 1; #endif str = SvPV(str_sv, len); - i_t1_bbox(fontnum,point,str,len,cords,utf8,flags); - EXTEND(SP, 6); - for (i = 0; i < 6; ++i) - PUSHs(sv_2mortal(newSViv(cords[i]))); + rc = i_t1_bbox(fontnum,point,str,len,cords,utf8,flags); + if (rc > 0) { + EXTEND(SP, rc); + for (i = 0; i < rc; ++i) + PUSHs(sv_2mortal(newSViv(cords[i]))); + } @@ -1756,6 +1927,89 @@ i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="") OUTPUT: RETVAL +void +i_t1_has_chars(handle, text_sv, utf8 = 0) + int handle + SV *text_sv + int utf8 + PREINIT: + char const *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_t1_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_t1_face_name(handle) + int handle + PREINIT: + char name[255]; + int len; + PPCODE: + len = i_t1_face_name(handle, name, sizeof(name)); + if (len) { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv(name, strlen(name)))); + } + +void +i_t1_glyph_name(handle, text_sv, utf8 = 0) + int handle + SV *text_sv + int utf8 + 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_t1_glyph_name(handle, ch, name, sizeof(name))) { + PUSHs(sv_2mortal(newSVpv(name, 0))); + } + else { + PUSHs(&PL_sv_undef); + } + } + #endif #ifdef HAVE_LIBTT @@ -1779,7 +2033,7 @@ MODULE = Imager PACKAGE = Imager undef_int -i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8) +i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im int xb @@ -1787,9 +2041,9 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8) Imager::Color cl float points SV * str_sv - int len_ignored int smooth int utf8 + int align PREINIT: char *str; STRLEN len; @@ -1800,13 +2054,13 @@ i_tt_text(handle,im,xb,yb,cl,points,str_sv,len_ignored,smooth,utf8) #endif str = SvPV(str_sv, len); RETVAL = i_tt_text(handle, im, xb, yb, cl, points, str, - len, smooth, utf8); + len, smooth, utf8, align); OUTPUT: RETVAL undef_int -i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8) +i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8,align=1) Imager::Font::TT handle Imager::ImgRaw im int xb @@ -1814,9 +2068,9 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8) int channel float points SV * str_sv - int len_ignored int smooth int utf8 + int align PREINIT: char *str; STRLEN len; @@ -1827,22 +2081,22 @@ i_tt_cp(handle,im,xb,yb,channel,points,str_sv,len_ignored,smooth,utf8) #endif str = SvPV(str_sv, len); RETVAL = i_tt_cp(handle, im, xb, yb, channel, points, str, len, - smooth, utf8); + smooth, utf8, align); OUTPUT: RETVAL -undef_int +void i_tt_bbox(handle,point,str_sv,len_ignored, utf8) Imager::Font::TT handle float point SV* str_sv - int len_ignored int utf8 PREINIT: - int cords[6],rc; + int cords[BOUNDING_BOX_COUNT],rc; char * str; STRLEN len; + int i; PPCODE: #ifdef SvUTF8 if (SvUTF8(ST(2))) @@ -1850,13 +2104,10 @@ i_tt_bbox(handle,point,str_sv,len_ignored, utf8) #endif str = SvPV(str_sv, len); if ((rc=i_tt_bbox(handle,point,str,len,cords, utf8))) { - EXTEND(SP, 4); - PUSHs(sv_2mortal(newSViv(cords[0]))); - PUSHs(sv_2mortal(newSViv(cords[1]))); - PUSHs(sv_2mortal(newSViv(cords[2]))); - PUSHs(sv_2mortal(newSViv(cords[3]))); - PUSHs(sv_2mortal(newSViv(cords[4]))); - PUSHs(sv_2mortal(newSViv(cords[5]))); + EXTEND(SP, rc); + for (i = 0; i < rc; ++i) { + PUSHs(sv_2mortal(newSViv(cords[i]))); + } } void @@ -1890,9 +2141,64 @@ i_tt_has_chars(handle, text_sv, utf8) } myfree(work); -#endif +void +i_tt_dump_names(handle) + Imager::Font::TT handle +void +i_tt_face_name(handle) + Imager::Font::TT handle + PREINIT: + char name[255]; + int len; + PPCODE: + len = i_tt_face_name(handle, name, sizeof(name)); + if (len) { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv(name, strlen(name)))); + } + +void +i_tt_glyph_name(handle, text_sv, utf8 = 0) + Imager::Font::TT handle + SV *text_sv + int utf8 + 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_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) { + PUSHs(sv_2mortal(newSVpv(name, 0))); + } + else { + PUSHs(&PL_sv_undef); + } + } +#endif #ifdef HAVE_LIBJPEG @@ -1928,18 +2234,26 @@ i_readjpeg_wiol(ig) myfree(iptc_itext); } +int +i_exif_enabled() #endif +const char * +i_test_format_probe(ig, length) + Imager::IO ig + int length + #ifdef HAVE_LIBTIFF Imager::ImgRaw -i_readtiff_wiol(ig, length) +i_readtiff_wiol(ig, length, page=0) Imager::IO ig int length + int page void i_readtiff_multi_wiol(ig, length) @@ -2108,7 +2422,7 @@ i_writegif(im,fd,colors,pixdev,fixed) sv1=(*(av_fetch(av,i,0))); if (sv_derived_from(sv1, "Imager::Color")) { Itmp = SvIV((SV*)SvRV(sv1)); - tmp = (i_color*) Itmp; + tmp = INT2PTR(i_color*, Itmp); } else croak("Imager: one of the elements of array ref is not of Imager::Color type\n"); fixed[i]=*tmp; } @@ -2379,6 +2693,11 @@ i_readgif_wiol(ig) PUSHs(newRV_noinc((SV*)ct)); } +Imager::ImgRaw +i_readgif_single_wiol(ig, page=0) + Imager::IO ig + int page + void i_readgif_scalar(...) PROTOTYPE: $ @@ -2432,8 +2751,6 @@ void i_readgif_callback(...) PROTOTYPE: & PREINIT: - char* data; - int length; int* colour_table; int colours, q, w; i_img* rimg; @@ -2607,8 +2924,6 @@ i_writetga_wiol(im,ig, wierdpack, compress, idstring) int compress char* idstring PREINIT: - SV* sv1; - int rc; int idlen; CODE: idlen = SvCUR(ST(4)); @@ -2631,8 +2946,6 @@ i_writergb_wiol(im,ig, wierdpack, compress, idstring) int compress char* idstring PREINIT: - SV* sv1; - int rc; int idlen; CODE: idlen = SvCUR(ST(4)); @@ -2660,6 +2973,12 @@ i_scale_nn(im,scx,scy) float scx float scy +Imager::ImgRaw +i_scale_mixing(im, width, height) + Imager::ImgRaw im + int width + int height + Imager::ImgRaw i_haar(im) Imager::ImgRaw im @@ -2720,11 +3039,17 @@ i_transform(im,opx,opy,parm) else sv_setref_pv(ST(0), "Imager::ImgRaw", (void*)RETVAL); Imager::ImgRaw -i_transform2(width,height,ops,n_regs,c_regs,in_imgs) +i_transform2(sv_width,sv_height,channels,sv_ops,av_n_regs,av_c_regs,av_in_imgs) + SV *sv_width + SV *sv_height + SV *sv_ops + AV *av_n_regs + AV *av_c_regs + AV *av_in_imgs + int channels PREINIT: int width; int height; - double* parm; struct rm_op *ops; STRLEN ops_len; int ops_count; @@ -2734,37 +3059,22 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs) int c_regs_count; int in_imgs_count; i_img **in_imgs; - AV* av; - SV* sv1; + SV *sv1; IV tmp; int i; CODE: - if (!SvROK(ST(3))) croak("Imager: Parameter 4 must be a reference to an array\n"); - if (!SvROK(ST(4))) croak("Imager: Parameter 5 must be a reference to an array\n"); - if (!SvROK(ST(5))) croak("Imager: Parameter 6 must be a reference to an array of images\n"); - if (SvTYPE(SvRV(ST(3))) != SVt_PVAV) croak("Imager: Parameter 4 must be a reference to an array\n"); - if (SvTYPE(SvRV(ST(4))) != SVt_PVAV) croak("Imager: Parameter 5 must be a reference to an array\n"); - - /*if (SvTYPE(SvRV(ST(5))) != SVt_PVAV) croak("Imager: Parameter 6 must be a reference to an array\n");*/ - - if (SvTYPE(SvRV(ST(5))) == SVt_PVAV) { - av = (AV*)SvRV(ST(5)); - in_imgs_count = av_len(av)+1; - for (i = 0; i < in_imgs_count; ++i) { - sv1 = *av_fetch(av, i, 0); - if (!sv_derived_from(sv1, "Imager::ImgRaw")) { - croak("Parameter 5 must contain only images"); - } + + in_imgs_count = av_len(av_in_imgs)+1; + for (i = 0; i < in_imgs_count; ++i) { + sv1 = *av_fetch(av_in_imgs, i, 0); + if (!sv_derived_from(sv1, "Imager::ImgRaw")) { + croak("sv_in_img must contain only images"); } } - else { - in_imgs_count = 0; - } if (in_imgs_count > 0) { - av = (AV*)SvRV(ST(5)); in_imgs = mymalloc(in_imgs_count*sizeof(i_img*)); for (i = 0; i < in_imgs_count; ++i) { - sv1 = *av_fetch(av,i,0); + sv1 = *av_fetch(av_in_imgs,i,0); if (!sv_derived_from(sv1, "Imager::ImgRaw")) { croak("Parameter 5 must contain only images"); } @@ -2777,38 +3087,37 @@ i_transform2(width,height,ops,n_regs,c_regs,in_imgs) in_imgs = NULL; } /* default the output size from the first input if possible */ - if (SvOK(ST(0))) - width = SvIV(ST(0)); + if (SvOK(sv_width)) + width = SvIV(sv_width); else if (in_imgs_count) width = in_imgs[0]->xsize; else croak("No output image width supplied"); - if (SvOK(ST(1))) - height = SvIV(ST(1)); + if (SvOK(sv_height)) + height = SvIV(sv_height); else if (in_imgs_count) height = in_imgs[0]->ysize; else croak("No output image height supplied"); - ops = (struct rm_op *)SvPV(ST(2), ops_len); + ops = (struct rm_op *)SvPV(sv_ops, ops_len); if (ops_len % sizeof(struct rm_op)) croak("Imager: Parameter 3 must be a bitmap of regops\n"); ops_count = ops_len / sizeof(struct rm_op); - av = (AV*)SvRV(ST(3)); - n_regs_count = av_len(av)+1; + + n_regs_count = av_len(av_n_regs)+1; n_regs = mymalloc(n_regs_count * sizeof(double)); for (i = 0; i < n_regs_count; ++i) { - sv1 = *av_fetch(av,i,0); + sv1 = *av_fetch(av_n_regs,i,0); if (SvOK(sv1)) n_regs[i] = SvNV(sv1); } - av = (AV*)SvRV(ST(4)); - c_regs_count = av_len(av)+1; + c_regs_count = av_len(av_c_regs)+1; c_regs = mymalloc(c_regs_count * sizeof(i_color)); /* I don't bother initializing the colou?r registers */ - RETVAL=i_transform2(width, height, 3, ops, ops_count, + RETVAL=i_transform2(width, height, channels, ops, ops_count, n_regs, n_regs_count, c_regs, c_regs_count, in_imgs, in_imgs_count); if (in_imgs) @@ -2962,7 +3271,7 @@ i_diff_image(im, im2, mindist=0) Imager::ImgRaw im2 int mindist -void +undef_int i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) Imager::ImgRaw im double xa @@ -2984,9 +3293,11 @@ i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_para asegs = (AV *)SvRV(ST(10)); segs = load_fount_segs(asegs, &count); - i_fountain(im, xa, ya, xb, yb, type, repeat, combine, super_sample, - ssample_param, count, segs); + RETVAL = i_fountain(im, xa, ya, xb, yb, type, repeat, combine, + super_sample, ssample_param, count, segs); myfree(segs); + OUTPUT: + RETVAL Imager::FillHandle i_new_fill_fount(xa, ya, xb, yb, type, repeat, combine, super_sample, ssample_param, segs) @@ -3021,7 +3332,6 @@ i_errors() i_errmsg *errors; int i; AV *av; - SV *ref; SV *sv; PPCODE: errors = i_errors(); @@ -3041,6 +3351,14 @@ i_errors() } void +i_clear_error() + +void +i_push_error(code, msg) + int code + const char *msg + +undef_int i_nearest_color(im, ...) Imager::ImgRaw im PREINIT: @@ -3085,26 +3403,13 @@ i_nearest_color(im, ...) } ival[i] = *INT2PTR(i_color *, SvIV((SV *)SvRV(sv))); } - i_nearest_color(im, num, xo, yo, ival, dmeasure); - - - + RETVAL = i_nearest_color(im, num, xo, yo, ival, dmeasure); + OUTPUT: + RETVAL void malloc_state() -void -hashinfo(hv) - PREINIT: - HV* hv; - int stuff; - PPCODE: - if (!SvROK(ST(0))) croak("Imager: Parameter 0 must be a reference to a hash\n"); - hv=(HV*)SvRV(ST(0)); - if (SvTYPE(hv)!=SVt_PVHV) croak("Imager: Parameter 0 must be a reference to a hash\n"); - if (getint(hv,"stuff",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n"); - if (getint(hv,"stuff2",&stuff)) printf("ok: %d\n",stuff); else printf("key doesn't exist\n"); - void DSO_open(filename) char* filename @@ -3160,7 +3465,6 @@ DSO_call(handle,func_index,hv) -# this is mostly for testing... SV * i_get_pixel(im, x, y) Imager::ImgRaw im @@ -3171,13 +3475,15 @@ i_get_pixel(im, x, y) CODE: color = (i_color *)mymalloc(sizeof(i_color)); if (i_gpix(im, x, y, color) == 0) { - ST(0) = sv_newmortal(); - sv_setref_pv(ST(0), "Imager::Color", (void *)color); + RETVAL = NEWSV(0, 0); + sv_setref_pv(RETVAL, "Imager::Color", (void *)color); } else { myfree(color); - ST(0) = &PL_sv_undef; + RETVAL = &PL_sv_undef; } + OUTPUT: + RETVAL int @@ -3258,13 +3564,14 @@ i_ppal(im, l, y, ...) int y PREINIT: i_palidx *work; - int count, i; + int i; CODE: if (items > 3) { work = mymalloc(sizeof(i_palidx) * (items-3)); 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); } @@ -3274,6 +3581,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 @@ -3293,22 +3622,24 @@ 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); myfree(colors); if (index == 0) { - ST(0) = sv_2mortal(newSVpv("0 but true", 0)); + RETVAL = newSVpv("0 but true", 0); } else if (index == -1) { - ST(0) = &PL_sv_undef; + RETVAL = &PL_sv_undef; } else { - ST(0) = sv_2mortal(newSViv(index)); + RETVAL = newSViv(index); } + OUTPUT: + RETVAL -int +undef_int i_setcolors(im, index, ...) Imager::ImgRaw im int index @@ -3332,6 +3663,8 @@ i_setcolors(im, index, ...) } RETVAL = i_setcolors(im, index, colors, items-2); myfree(colors); + OUTPUT: + RETVAL void i_getcolors(im, index, ...) @@ -3362,33 +3695,13 @@ i_getcolors(im, index, ...) myfree(colors); -SV * +undef_neg_int i_colorcount(im) Imager::ImgRaw im - PREINIT: - int count; - CODE: - count = i_colorcount(im); - if (count >= 0) { - ST(0) = sv_2mortal(newSViv(count)); - } - else { - ST(0) = &PL_sv_undef; - } -SV * +undef_neg_int i_maxcolors(im) Imager::ImgRaw im - PREINIT: - int count; - CODE: - count = i_maxcolors(im); - if (count >= 0) { - ST(0) = sv_2mortal(newSViv(count)); - } - else { - ST(0) = &PL_sv_undef; - } SV * i_findcolor(im, color) @@ -3398,11 +3711,13 @@ i_findcolor(im, color) i_palidx index; CODE: if (i_findcolor(im, color, &index)) { - ST(0) = sv_2mortal(newSViv(index)); + RETVAL = newSViv(index); } else { - ST(0) = &PL_sv_undef; + RETVAL = &PL_sv_undef; } + OUTPUT: + RETVAL int i_img_bits(im) @@ -3487,24 +3802,36 @@ i_plin(im, l, y, ...) int y PREINIT: i_color *work; - int count, i; + 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; @@ -3540,6 +3867,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) @@ -3549,6 +3877,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) { @@ -3564,24 +3893,37 @@ i_plinf(im, l, y, ...) int y PREINIT: i_fcolor *work; - int count, i; + 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; @@ -3599,14 +3941,16 @@ i_gpixf(im, x, y) CODE: color = (i_fcolor *)mymalloc(sizeof(i_fcolor)); if (i_gpixf(im, x, y, color) == 0) { - ST(0) = sv_newmortal(); - sv_setref_pv(ST(0), "Imager::Color::Float", (void *)color); + RETVAL = NEWSV(0,0); + sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color); } else { myfree(color); - ST(0) = &PL_sv_undef; + RETVAL = &PL_sv_undef; } - + OUTPUT: + RETVAL + void i_glin(im, l, r, y) Imager::ImgRaw im @@ -3620,13 +3964,20 @@ i_glin(im, l, r, y) if (l < r) { vals = mymalloc((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)); - 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); } @@ -3644,14 +3995,20 @@ i_glinf(im, l, r, y) if (l < r) { vals = mymalloc((r-l) * sizeof(i_fcolor)); 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); } @@ -3719,12 +4076,14 @@ i_tags_find(im, name, start) CODE: if (i_tags_find(&im->tags, name, start, &entry)) { if (entry == 0) - ST(0) = sv_2mortal(newSVpv("0 but true", 0)); + RETVAL = newSVpv("0 but true", 0); else - ST(0) = sv_2mortal(newSViv(entry)); + RETVAL = newSViv(entry); } else { - ST(0) = &PL_sv_undef; + RETVAL = &PL_sv_undef; } + OUTPUT: + RETVAL SV * i_tags_findn(im, code, start) @@ -3736,12 +4095,15 @@ i_tags_findn(im, code, start) CODE: if (i_tags_findn(&im->tags, code, start, &entry)) { if (entry == 0) - ST(0) = sv_2mortal(newSVpv("0 but true", 0)); + RETVAL = newSVpv("0 but true", 0); else - ST(0) = sv_2mortal(newSViv(entry)); + RETVAL = newSViv(entry); } - else - ST(0) = &PL_sv_undef; + else { + RETVAL = &PL_sv_undef; + } + OUTPUT: + RETVAL int i_tags_delete(im, entry) @@ -3793,6 +4155,28 @@ i_tags_get(im, index) } } +void +i_tags_get_string(im, what_sv) + Imager::ImgRaw im + SV *what_sv + PREINIT: + char const *name = NULL; + int code; + char buffer[200]; + PPCODE: + if (SvIOK(what_sv)) { + code = SvIV(what_sv); + name = NULL; + } + else { + name = SvPV_nolen(what_sv); + code = 0; + } + if (i_tags_get_string(&im->tags, name, code, buffer, sizeof(buffer))) { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv(buffer, 0))); + } + int i_tags_count(im) Imager::ImgRaw im @@ -3804,57 +4188,83 @@ i_tags_count(im) #ifdef HAVE_WIN32 void -i_wf_bbox(face, size, text) +i_wf_bbox(face, size, text_sv, utf8=0) char *face int size - char *text + SV *text_sv + int utf8 PREINIT: - int cords[6]; + int cords[BOUNDING_BOX_COUNT]; + int rc, i; + char const *text; + STRLEN text_len; PPCODE: - if (i_wf_bbox(face, size, text, strlen(text), cords)) { - EXTEND(SP, 6); - PUSHs(sv_2mortal(newSViv(cords[0]))); - PUSHs(sv_2mortal(newSViv(cords[1]))); - PUSHs(sv_2mortal(newSViv(cords[2]))); - PUSHs(sv_2mortal(newSViv(cords[3]))); - PUSHs(sv_2mortal(newSViv(cords[4]))); - PUSHs(sv_2mortal(newSViv(cords[5]))); + text = SvPV(text_sv, text_len); +#ifdef SvUTF8 + if (SvUTF8(text_sv)) + utf8 = 1; +#endif + if (rc = i_wf_bbox(face, size, text, text_len, cords, utf8)) { + 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) +i_wf_text(face, im, tx, ty, cl, size, text_sv, align, aa, utf8 = 0) char *face Imager::ImgRaw im int tx int ty Imager::Color cl int size - char *text + SV *text_sv int align int aa + int utf8 + PREINIT: + char const *text; + STRLEN text_len; CODE: - RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, strlen(text), - align, aa); + text = SvPV(text_sv, text_len); +#ifdef SvUTF8 + if (SvUTF8(text_sv)) + utf8 = 1; +#endif + RETVAL = i_wf_text(face, im, tx, ty, cl, size, text, text_len, + align, aa, utf8); OUTPUT: RETVAL undef_int -i_wf_cp(face, im, tx, ty, channel, size, text, align, aa) +i_wf_cp(face, im, tx, ty, channel, size, text_sv, align, aa, utf8 = 0) char *face Imager::ImgRaw im int tx int ty int channel int size - char *text + SV *text_sv int align int aa + int utf8 + PREINIT: + char const *text; + STRLEN text_len; CODE: - RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, strlen(text), - align, aa); + text = SvPV(text_sv, text_len); +#ifdef SvUTF8 + if (SvUTF8(text_sv)) + utf8 = 1; +#endif + RETVAL = i_wf_cp(face, im, tx, ty, channel, size, text, text_len, + align, aa, utf8); OUTPUT: RETVAL +undef_int +i_wf_addfont(font) + char *font #endif @@ -3925,23 +4335,28 @@ i_ft2_settransform(font, matrix) RETVAL void -i_ft2_bbox(font, cheight, cwidth, text, utf8) +i_ft2_bbox(font, cheight, cwidth, text_sv, utf8) Imager::Font::FT2 font double cheight double cwidth - char *text + SV *text_sv int utf8 PREINIT: - int bbox[6]; + 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(ST(3))) + if (SvUTF8(text_sv)) utf8 = 1; #endif - if (i_ft2_bbox(font, cheight, cwidth, text, strlen(text), bbox, utf8)) { - EXTEND(SP, 6); - for (i = 0; i < 6; ++i) + 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]))); } @@ -3997,7 +4412,7 @@ i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8 RETVAL undef_int -i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, utf8) +i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8) Imager::Font::FT2 font Imager::ImgRaw im int tx @@ -4005,18 +4420,22 @@ i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, align, aa, vlayout, u int channel double cheight double cwidth - char *text + SV *text_sv int align int aa int vlayout int utf8 + PREINIT: + char const *text; + STRLEN len; CODE: #ifdef SvUTF8 if (SvUTF8(ST(7))) utf8 = 1; #endif + text = SvPV(text_sv, len); RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, - strlen(text), align, aa, vlayout, 1); + len, align, aa, vlayout, 1); OUTPUT: RETVAL @@ -4069,6 +4488,122 @@ i_ft2_has_chars(handle, text_sv, utf8) } 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_ @@ -4166,3 +4701,43 @@ i_new_fill_image(src, matrix, xoff, yoff, combine) RETVAL = i_new_fill_image(src, matrixp, 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 + +#endif + +BOOT: + PERL_SET_GLOBAL_CALLBACKS;