X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/9a88a5e6b7a2a685d04c1c18d402a3735e5a3e37..855c5808a2661ad4b3b13a552dc05feb949012a7:/image.c diff --git a/image.c b/image.c index 2f549866..eba037c5 100644 --- a/image.c +++ b/image.c @@ -1,6 +1,5 @@ #include "image.h" #include "imagei.h" -#include "io.h" /* =head1 NAME @@ -26,7 +25,7 @@ color objects for Imager. Some of these functions are internal. -=over 4 +=over =cut */ @@ -38,7 +37,7 @@ Some of these functions are internal. #define minmax(a,b,i) ( ((a>=i)?a: ( (b<=i)?b:i )) ) /* Hack around an obscure linker bug on solaris - probably due to builtin gcc thingies */ -void fake(void) { ceil(1); } +static void fake(void) { ceil(1); } static int i_ppix_d(i_img *im, int x, int y, i_color *val); static int i_gpix_d(i_img *im, int x, int y, i_color *val); @@ -48,8 +47,10 @@ static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val); static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val); static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals); -static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); -static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count); +static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count); +static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count); +/*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); + static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/ /* =item ICL_new_internal(r, g, b, a) @@ -347,7 +348,25 @@ Re-new image reference i_img * i_img_empty_ch(i_img *im,int x,int y,int ch) { + int bytes; + mm_log((1,"i_img_empty_ch(*im %p, x %d, y %d, ch %d)\n", im, x, y, ch)); + + if (x < 1 || y < 1) { + i_push_error(0, "Image sizes must be positive"); + return NULL; + } + if (ch < 1 || ch > MAXCHANNELS) { + i_push_errorf(0, "channels must be between 1 and %d", MAXCHANNELS); + return NULL; + } + /* check this multiplication doesn't overflow */ + bytes = x*y*ch; + if (bytes / y / ch != x) { + i_push_errorf(0, "integer overflow calculating image allocation"); + return NULL; + } + if (im == NULL) if ( (im=mymalloc(sizeof(i_img))) == NULL) m_fatal(2,"malloc() error\n"); @@ -358,8 +377,9 @@ i_img_empty_ch(i_img *im,int x,int y,int ch) { im->ysize = y; im->channels = ch; im->ch_mask = MAXINT; - im->bytes=x*y*im->channels; - if ( (im->idata=mymalloc(im->bytes)) == NULL) m_fatal(2,"malloc() error\n"); + im->bytes=bytes; + if ( (im->idata=mymalloc(im->bytes)) == NULL) + m_fatal(2,"malloc() error\n"); memset(im->idata,0,(size_t)im->bytes); im->ext_data = NULL; @@ -483,50 +503,6 @@ int i_img_getchannels(i_img *im) { return im->channels; } -/* -=item i_ppix(im, x, y, col) - -Sets the pixel at (I,I) in I to I. - -Returns true if the pixel could be set, false if x or y is out of -range. - -=cut -*/ -int -(i_ppix)(i_img *im, int x, int y, i_color *val) { return im->i_f_ppix(im, x, y, val); } - -/* -=item i_gpix(im, x, y, &col) - -Get the pixel at (I,I) in I into I. - -Returns true if the pixel could be retrieved, false otherwise. - -=cut -*/ -int -(i_gpix)(i_img *im, int x, int y, i_color *val) { return im->i_f_gpix(im, x, y, val); } - -/* -=item i_ppix_pch(im, x, y, ch) - -Get the value from the channel I for pixel (I,I) from I -scaled to [0,1]. - -Returns zero if x or y is out of range. - -Warning: this ignores the vptr interface for images. - -=cut -*/ -float -i_gpix_pch(i_img *im,int x,int y,int ch) { - /* FIXME */ - if (x>-1 && xxsize && y>-1 && yysize) return ((float)im->idata[(x+y*im->xsize)*im->channels+ch]/255); - else return 0; -} - /* =item i_copyto_trans(im, src, x1, y1, x2, y2, tx, ty, trans) @@ -691,9 +667,10 @@ i_copy(i_img *im, i_img *src) { /* -=item i_rubthru(im, src, tx, ty) +=item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy ) -Takes the image I and applies it at an original (I,I) in I. +Takes the sub image I and +overlays it at (I,I) on the image object. The alpha channel of each pixel in I is used to control how much the existing colour in I is replaced, if it is 255 then the colour @@ -704,14 +681,17 @@ unmodified. */ int -i_rubthru(i_img *im,i_img *src,int tx,int ty) { +i_rubthru(i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny, + int src_maxx, int src_maxy) { int x, y, ttx, tty; int chancount; int chans[3]; int alphachan; int ch; - mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d)\n", im, src, tx, ty)); + mm_log((1,"i_rubthru(im %p, src %p, tx %d, ty %d, src_minx %d, " + "src_miny %d, src_maxx %d, src_maxy %d)\n", + im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy)); i_clear_error(); if (im->channels == 3 && src->channels == 4) { @@ -739,11 +719,10 @@ i_rubthru(i_img *im,i_img *src,int tx,int ty) { changed in a similar fashion - TC */ int alpha; i_color pv, orig, dest; - ttx = tx; - for(x=0; xxsize; x++) { - tty=ty; - for(y=0;yysize;y++) { - /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */ + tty = ty; + for(y = src_miny; y < src_maxy; y++) { + ttx = tx; + for(x = src_minx; x < src_maxx; x++) { i_gpix(src, x, y, &pv); i_gpix(im, ttx, tty, &orig); alpha = pv.channel[alphachan]; @@ -752,31 +731,30 @@ i_rubthru(i_img *im,i_img *src,int tx,int ty) { + (255 - alpha) * orig.channel[ch])/255; } i_ppix(im, ttx, tty, &dest); - tty++; + ttx++; } - ttx++; + tty++; } } else { double alpha; i_fcolor pv, orig, dest; - ttx = tx; - for(x=0; xxsize; x++) { - tty=ty; - for(y=0;yysize;y++) { - /* fprintf(stderr,"reading (%d,%d) writing (%d,%d).\n",x,y,ttx,tty); */ + tty = ty; + for(y = src_miny; y < src_maxy; y++) { + ttx = tx; + for(x = src_minx; x < src_maxx; x++) { i_gpixf(src, x, y, &pv); i_gpixf(im, ttx, tty, &orig); alpha = pv.channel[alphachan]; for (ch = 0; ch < chancount; ++ch) { dest.channel[ch] = alpha * pv.channel[chans[ch]] - + (1 - alpha) * orig.channel[ch]; + + (1 - alpha) * orig.channel[ch]; } i_ppixf(im, ttx, tty, &dest); - tty++; + ttx++; } - ttx++; + tty++; } } @@ -909,6 +887,7 @@ Lanczos(float x) { else return(sin(PIx) / PIx * sin(PIx2) / PIx2); } + /* =item i_scaleaxis(im, value, axis) @@ -932,8 +911,13 @@ i_scaleaxis(i_img *im, float Value, int Axis) { mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis)); + if (Axis == XAXIS) { hsize = (int)(0.5 + im->xsize * Value); + if (hsize < 1) { + hsize = 1; + Value = 1.0 / im->xsize; + } vsize = im->ysize; jEnd = hsize; @@ -942,6 +926,11 @@ i_scaleaxis(i_img *im, float Value, int Axis) { hsize = im->xsize; vsize = (int)(0.5 + im->ysize * Value); + if (vsize < 1) { + vsize = 1; + Value = 1.0 / im->ysize; + } + jEnd = vsize; iEnd = hsize; } @@ -1059,7 +1048,15 @@ i_scale_nn(i_img *im, float scx, float scy) { mm_log((1,"i_scale_nn(im 0x%x,scx %.2f,scy %.2f)\n",im,scx,scy)); nxsize = (int) ((float) im->xsize * scx); + if (nxsize < 1) { + nxsize = 1; + scx = 1 / im->xsize; + } nysize = (int) ((float) im->ysize * scy); + if (nysize < 1) { + nysize = 1; + scy = 1 / im->ysize; + } new_img=i_img_empty_ch(NULL,nxsize,nysize,im->channels); @@ -1113,6 +1110,32 @@ i_img *i_sametype(i_img *src, int xsize, int ysize) { } } +/* +=item i_sametype_chans(i_img *im, int xsize, int ysize, int channels) + +Returns an image of the same type (sample size). + +For paletted images the equivalent direct type is returned. + +=cut +*/ + +i_img *i_sametype_chans(i_img *src, int xsize, int ysize, int channels) { + if (src->bits == 8) { + return i_img_empty_ch(NULL, xsize, ysize, channels); + } + else if (src->bits == i_16_bits) { + return i_img_16_new(xsize, ysize, channels); + } + else if (src->bits == i_double_bits) { + return i_img_double_new(xsize, ysize, channels); + } + else { + i_push_error(0, "Unknown image bits"); + return NULL; + } +} + /* =item i_transform(im, opx, opxl, opy, opyl, parm, parmlen) @@ -1154,8 +1177,8 @@ i_transform(i_img *im, int *opx,int opxl,int *opy,int opyl,double parm[],int par parm[1]=(double)ny; /* fprintf(stderr,"(%d,%d) ->",nx,ny); */ - rx=op_run(opx,opxl,parm,parmlen); - ry=op_run(opy,opyl,parm,parmlen); + rx=i_op_run(opx,opxl,parm,parmlen); + ry=i_op_run(opy,opyl,parm,parmlen); /* fprintf(stderr,"(%f,%f)\n",rx,ry); */ i_gpix(im,rx,ry,&val); i_ppix(new_img,nx,ny,&val); @@ -1283,13 +1306,6 @@ i_count_colors(i_img *im,int maxc) { return colorcnt; } - -symbol_table_t symbol_table={i_has_format,ICL_set_internal,ICL_info, - i_img_new,i_img_empty,i_img_empty_ch,i_img_exorcise, - i_img_info,i_img_setmask,i_img_getmask,i_ppix,i_gpix, - i_box,i_draw,i_arc,i_copyto,i_copyto_trans,i_rubthru}; - - /* =back @@ -1310,6 +1326,7 @@ Returns 0 if the pixel could be set, -1 otherwise. =cut */ +static int i_ppix_d(i_img *im, int x, int y, i_color *val) { int ch; @@ -1335,12 +1352,13 @@ Returns 0 if the pixel could be set, -1 otherwise. =cut */ +static int i_gpix_d(i_img *im, int x, int y, i_color *val) { int ch; if (x>-1 && xxsize && y>-1 && yysize) { for(ch=0;chchannels;ch++) - val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch]; + val->channel[ch]=im->idata[(x+y*im->xsize)*im->channels+ch]; return 0; } for(ch=0;chchannels;ch++) val->channel[ch] = 0; @@ -1363,6 +1381,7 @@ Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ +static int i_glin_d(i_img *im, int l, int r, int y, i_color *vals) { int ch, count, i; @@ -1399,6 +1418,7 @@ Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ +static int i_plin_d(i_img *im, int l, int r, int y, i_color *vals) { int ch, count, i; @@ -1427,6 +1447,7 @@ i_plin_d(i_img *im, int l, int r, int y, i_color *vals) { =cut */ +static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) { int ch; @@ -1447,6 +1468,7 @@ i_ppixf_d(i_img *im, int x, int y, i_fcolor *val) { =cut */ +static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val) { int ch; @@ -1476,6 +1498,7 @@ Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ +static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) { int ch, count, i; @@ -1512,6 +1535,7 @@ Returns the number of pixels copied (eg. if r, l or y is out of range) =cut */ +static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals) { int ch, count, i; @@ -1546,8 +1570,10 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) =cut */ -int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count) { +static +int +i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, + const int *chans, int chan_count) { int ch, count, i, w; unsigned char *data; @@ -1602,8 +1628,10 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) =cut */ -int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count) { +static +int +i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, + const int *chans, int chan_count) { int ch, count, i, w; unsigned char *data; for (ch = 0; ch < chan_count; ++ch) { @@ -1765,7 +1793,7 @@ int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) { =cut */ int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, - int *chans, int chan_count) { + int const *chans, int chan_count) { i_sample_t *work; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { @@ -1908,7 +1936,7 @@ i_gen_reader(i_gen_read_data *gci, char *buf, int length) { gci->cpos = 0; gci->length = did_read; - copy_size = min(length, gci->length); + copy_size = i_min(length, gci->length); memcpy(buf, gci->buffer, copy_size); gci->cpos += copy_size; buf += copy_size; @@ -1951,13 +1979,13 @@ i_gen_read_data_new(i_read_callback_t cb, char *userdata) { } /* -=item free_gen_read_data(i_gen_read_data *) +=item i_free_gen_read_data(i_gen_read_data *) Cleans up. =cut */ -void free_gen_read_data(i_gen_read_data *self) { +void i_free_gen_read_data(i_gen_read_data *self) { myfree(self); } @@ -2001,7 +2029,7 @@ int size) Allocates and initializes the data structure used by i_gen_writer. -This should be released with L +This should be released with L =cut */ @@ -2011,7 +2039,7 @@ i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, i_gen_write_data *self = mymalloc(sizeof(i_gen_write_data)); self->cb = cb; self->userdata = userdata; - self->maxlength = min(max_length, sizeof(self->buffer)); + self->maxlength = i_min(max_length, sizeof(self->buffer)); if (self->maxlength < 0) self->maxlength = sizeof(self->buffer); self->filledto = 0; @@ -2020,7 +2048,7 @@ i_gen_write_data *i_gen_write_data_new(i_write_callback_t cb, } /* -=item free_gen_write_data(i_gen_write_data *info, int flush) +=item i_free_gen_write_data(i_gen_write_data *info, int flush) Cleans up the write buffer. @@ -2034,7 +2062,7 @@ ie. if it fails. =cut */ -int free_gen_write_data(i_gen_write_data *info, int flush) +int i_free_gen_write_data(i_gen_write_data *info, int flush) { int result = !flush || info->filledto == 0 || @@ -2044,9 +2072,89 @@ int free_gen_write_data(i_gen_write_data *info, int flush) return result; } + + +/* +=item i_test_format_probe(io_glue *data, int length) + +Check the beginning of the supplied file for a 'magic number' + +=cut +*/ + + +char * +i_test_format_probe(io_glue *data, int length) { + + static struct { + char *magic; + char *name; + } formats[] = { + {"\xFF\xD8", "jpeg"}, + {"GIF87a", "gif"}, + {"GIF89a", "gif"}, + {"MM\0*", "tiff"}, + {"II*\0", "tiff"}, + {"BM", "bmp"}, + {"\x89PNG\x0d\x0a\x1a\x0a", "png"}, + {"P1", "pnm"}, + {"P2", "pnm"}, + {"P3", "pnm"}, + {"P4", "pnm"}, + {"P5", "pnm"}, + {"P6", "pnm"}, + }; + unsigned int i; + char head[18]; + char *match = NULL; + ssize_t rc; + + io_glue_commit_types(data); + rc = data->readcb(data, head, 18); + if (rc == -1) return NULL; + data->seekcb(data, -rc, SEEK_CUR); + + for(i=0; ireadcb(data, head, 18); + if (rc == -1) return NULL; + x0 = (unsigned char)head[0]; + x1 = (unsigned char)head[1]; + data->seekcb(data, -rc, SEEK_CUR); + printf("Jpeg reread: %x %x\n", x0, x1); + } + */ + + if (!match && + (rc == 18) && + tga_header_verify(head)) return "tga"; + return match; +} + + + + /* =back +=head1 AUTHOR + +Arnar M. Hrafnkelsson + +Tony Cook + =head1 SEE ALSO L, L