]> git.imager.perl.org - imager.git/blobdiff - image.c
- fixes to verbose mode in Makefile.PL, also added a -v switch so you
[imager.git] / image.c
diff --git a/image.c b/image.c
index 8bad545848dd8e50e406154007b5b97570762419..eba037c5d0c1a1bcb55e8bff032b1cc6da519a7d 100644 (file)
--- a/image.c
+++ b/image.c
@@ -1,6 +1,5 @@
 #include "image.h"
 #include "imagei.h"
-#include "io.h"
 
 /*
 =head1 NAME
@@ -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<x>,I<y>) in I<im> to I<col>.
-
-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<x>,I<y>) in I<im> into I<col>.
-
-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<ch> for pixel (I<x>,I<y>) from I<im>
-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 && x<im->xsize && y>-1 && y<im->ysize) 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<src> and applies it at an original (I<tx>,I<ty>) in I<im>.
+Takes the sub image I<src[src_minx, src_maxx)[src_miny, src_maxy)> and
+overlays it at (I<tx>,I<ty>) on the image object.
 
 The alpha channel of each pixel in I<src> is used to control how much
 the existing colour in I<im> 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; x<src->xsize; x++) {
-      tty=ty;
-      for(y=0;y<src->ysize;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; x<src->xsize; x++) {
-      tty=ty;
-      for(y=0;y<src->ysize;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
 
@@ -1557,7 +1573,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
 static
 int
 i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, 
-              int *chans, int chan_count) {
+              const int *chans, int chan_count) {
   int ch, count, i, w;
   unsigned char *data;
 
@@ -1615,7 +1631,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask)
 static
 int
 i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, 
-               int *chans, int chan_count) {
+           const int *chans, int chan_count) {
   int ch, count, i, w;
   unsigned char *data;
   for (ch = 0; ch < chan_count; ++ch) {
@@ -1777,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) {
@@ -1920,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;
@@ -1963,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);
 }
 
@@ -2013,7 +2029,7 @@ int size)
 
 Allocates and initializes the data structure used by i_gen_writer.
 
-This should be released with L<image.c/free_gen_write_data>
+This should be released with L<image.c/i_free_gen_write_data>
 
 =cut
 */
@@ -2023,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;
@@ -2032,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.
 
@@ -2046,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 ||
@@ -2056,6 +2072,80 @@ 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; i<sizeof(formats)/sizeof(formats[0]); i++) { 
+    int c;
+    ssize_t len = strlen(formats[i].magic);
+    if (rc<len) continue;
+    c = !strncmp(formats[i].magic, head, len);
+    if (c) {
+      match = formats[i].name;
+      break;
+    }
+  }
+
+  /*
+    if (match && !strcmp(match, "jpeg")) {
+    unsigned int x0, x1;
+    rc = data->readcb(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