]> git.imager.perl.org - imager.git/blobdiff - image.c
More debugging for auto probing of image types.
[imager.git] / image.c
diff --git a/image.c b/image.c
index d4c3f6f400116ef069fce1ed2564088143adfc50..9448faf0e1c1b6c119f728fe07a8a8ebb45312b6 100644 (file)
--- a/image.c
+++ b/image.c
@@ -26,7 +26,7 @@ color objects for Imager.
 
 Some of these functions are internal.
 
-=over 4
+=over
 
 =cut
 */
@@ -38,7 +38,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 +48,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)
@@ -202,7 +204,7 @@ static i_img IIM_base_8bit_direct =
 {
   0, /* channels set */
   0, 0, 0, /* xsize, ysize, bytes */
-  ~0, /* ch_mask */
+  ~0U, /* ch_mask */
   i_8_bits, /* bits */
   i_direct_type, /* type */
   0, /* virtual */
@@ -409,7 +411,7 @@ Destroy image and free data via exorcise.
 
 void
 i_img_destroy(i_img *im) {
-  mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
+  mm_log((1,"i_img_destroy(im %p)\n",im));
   i_img_exorcise(im);
   if (im) { myfree(im); }
 }
@@ -483,50 +485,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)
@@ -909,6 +867,99 @@ Lanczos(float x) {
   else return(sin(PIx) / PIx * sin(PIx2) / PIx2);
 }
 
+
+
+
+
+
+
+
+
+i_img*
+i_scaleaxis_3ch_8bit(i_img *im, int size, int Axis) {
+
+  int i, j;
+  int iEnd, jEnd;
+
+  int hsize, vsize;
+
+  short psave;
+  unsigned long *pixels;
+  i_color val;
+  i_img *new_img;
+
+  mm_log((1,"i_scaleaxis_3ch_8bit(im %p, size %d,Axis %d)\n",im, size, Axis));
+
+  if (Axis == XAXIS) {
+    hsize = size;
+    vsize = im->ysize;
+    
+    jEnd = hsize;
+    iEnd = vsize;
+    pixels = mymalloc(sizeof(*pixels) * im->xsize);
+  } else {
+    hsize = im->xsize;
+    vsize = size;
+    
+    jEnd = vsize;
+    iEnd = hsize;
+    pixels = mymalloc(sizeof(*pixels) * im->ysize);
+  }
+  
+  new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
+
+
+  if (Axis == XAXIS) {
+    
+    for (i=0; i<iEnd; i++) {
+      int end = im->xsize;
+
+      for(j=0; j<im->xsize; j++) {
+       i_gpix(im, j, i, &val);
+       pixels[j] = (val.rgba.r<<24) | (val.rgba.g<<16) | (val.rgba.b<<8) | (val.rgba.a<<0);
+      }
+      
+      /* printf("jEnd = %d, end = %d\n", jEnd, end); */
+      while ((end+1)/2>=size) {
+       int lend = end/2;
+       end = (end+1) / 2;
+       
+       for(j=0; j<lend; j++) {
+         unsigned long a = pixels[2*j];
+         unsigned long b = pixels[2*j+1];
+         pixels[j] = (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+       }
+       if (end>lend) {
+         pixels[j] = pixels[2*j];
+         j++;
+       }
+      }
+
+      printf("end = %d size = %d\n", end, size);
+
+      /* Replace this with Bresenham later */
+      for(j=0; j<size; j++) {
+       float f = i;
+         /*    if ((i*size)/end <)  */
+         unsigned long t = pixels[j];
+       val.rgba.r = (t >> 24) & 0xff;
+       val.rgba.g = (t >> 16) & 0xff;
+       val.rgba.b = (t >> 8) & 0xff;
+       val.rgba.a = t & 0xff;
+       i_ppix(new_img, j, i, &val);
+      }
+    }
+  }
+  
+  return new_img;
+}
+
+
+
+
+
+
+
 /*
 =item i_scaleaxis(im, value, axis)
 
@@ -923,71 +974,87 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
   int LanczosWidthFactor;
   float *l0, *l1, OldLocation;
-  int T, TempJump1, TempJump2;
+  int T; 
+  float t;
   float F, PictureValue[MAXCHANNELS];
   short psave;
   i_color val,val1,val2;
   i_img *new_img;
 
-  mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
+  mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
+
 
   if (Axis == XAXIS) {
-    hsize = (int) ((float) im->xsize * Value);
+    return i_scaleaxis_3ch_8bit(im, (int)(0.5+im->xsize*Value), Axis);
+
+    hsize = (int)(0.5 + im->xsize * Value);
     vsize = im->ysize;
     
     jEnd = hsize;
     iEnd = vsize;
-    
-    TempJump1 = (hsize - 1) * 3;
-    TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
   } else {
     hsize = im->xsize;
-    vsize = (int) ((float) im->ysize * Value);
-    
+    vsize = (int)(0.5 + im->ysize * Value);
+
     jEnd = vsize;
     iEnd = hsize;
-    
-    TempJump1 = 0;
-    TempJump2 = 0;
   }
   
-  new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
-  
-  if (Value >=1) LanczosWidthFactor = 1;
-  else LanczosWidthFactor = (int) (1.0/Value);
+  new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
   
+  /* 1.4 is a magic number, setting it to 2 will cause rather blurred images */
+  LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value); 
   lMax = LanczosWidthFactor << 1;
   
-  l0 = (float *) mymalloc(lMax * sizeof(float));
-  l1 = (float *) mymalloc(lMax * sizeof(float));
+  l0 = mymalloc(lMax * sizeof(float));
+  l1 = mymalloc(lMax * sizeof(float));
   
   for (j=0; j<jEnd; j++) {
     OldLocation = ((float) j) / Value;
     T = (int) (OldLocation);
     F = OldLocation - (float) T;
     
-    for (l = 0; l < lMax; l++) {
+    for (l = 0; l<lMax; l++) {
       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
-      l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
+      l1[l]        = Lanczos(((float) (l+1)      - F) / (float) LanczosWidthFactor);
     }
     
-    if (Axis== XAXIS) {
+    /* Make sure filter is normalized */
+    t = 0.0;
+    for(l=0; l<lMax; l++) {
+      t+=l0[l];
+      t+=l1[l];
+    }
+    t /= (float)LanczosWidthFactor;
+    
+    for(l=0; l<lMax; l++) {
+      l0[l] /= t;
+      l1[l] /= t;
+    }
+
+    if (Axis == XAXIS) {
       
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
-       for (l=0; l < lMax; l++) {
-         i_gpix(im,T+l+1, i, &val1);
-         i_gpix(im,T-lMax+l+1, i, &val2);
+       for (l=0; l<lMax; l++) {
+         int mx = T-lMax+l+1;
+         int Mx = T+l+1;
+         mx = (mx < 0) ? 0 : mx;
+         Mx = (Mx >= im->xsize) ? im->xsize-1 : Mx;
+         
+         i_gpix(im, Mx, i, &val1);
+         i_gpix(im, mx, i, &val2);
+         
          for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l] * val1.channel[k];
+           PictureValue[k] += l1[l]        * val1.channel[k];
            PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
          }
        }
        for(k=0;k<im->channels;k++) {
-         psave = (short)( PictureValue[k] / LanczosWidthFactor);
+         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
          val.channel[k]=minmax(0,255,psave);
        }
-       i_ppix(new_img,j,i,&val);
+       i_ppix(new_img, j, i, &val);
       }
       
     } else {
@@ -995,18 +1062,23 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l < lMax; l++) {
-         i_gpix(im,i, T+l+1, &val1);
-         i_gpix(im,i, T-lMax+l+1, &val2);
+         int mx = T-lMax+l+1;
+         int Mx = T+l+1;
+         mx = (mx < 0) ? 0 : mx;
+         Mx = (Mx >= im->ysize) ? im->ysize-1 : Mx;
+
+         i_gpix(im, i, Mx, &val1);
+         i_gpix(im, i, mx, &val2);
          for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l] * val1.channel[k];
+           PictureValue[k] += l1[l]        * val1.channel[k];
            PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
          }
        }
        for (k=0; k<im->channels; k++) {
-         psave = (short)( PictureValue[k] / LanczosWidthFactor);
-         val.channel[k]=minmax(0,255,psave);
+         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
+         val.channel[k] = minmax(0, 255, psave);
        }
-       i_ppix(new_img,i,j,&val);
+       i_ppix(new_img, i, j, &val);
       }
       
     }
@@ -1014,7 +1086,7 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   myfree(l0);
   myfree(l1);
 
-  mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
+  mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
 
   return new_img;
 }
@@ -1095,6 +1167,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)
 
@@ -1136,8 +1234,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);
@@ -1265,13 +1363,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
 
@@ -1292,6 +1383,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;
@@ -1317,14 +1409,16 @@ 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 && x<im->xsize && y>-1 && y<im->ysize) {
     for(ch=0;ch<im->channels;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;ch<im->channels;ch++) val->channel[ch] = 0;
   return -1; /* error was cliped */
 }
 
@@ -1344,6 +1438,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;
@@ -1380,6 +1475,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;
@@ -1408,6 +1504,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;
@@ -1428,6 +1525,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;
@@ -1457,6 +1555,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;
@@ -1493,6 +1592,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;
@@ -1527,8 +1627,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;
 
@@ -1583,8 +1685,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) {
@@ -1746,7 +1850,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) {
@@ -1889,7 +1993,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;
@@ -1932,13 +2036,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);
 }
 
@@ -1982,7 +2086,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
 */
@@ -1992,7 +2096,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;
@@ -2001,7 +2105,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.
 
@@ -2015,7 +2119,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 ||
@@ -2025,9 +2129,94 @@ int free_gen_write_data(i_gen_write_data *info, int flush)
   return result;
 }
 
+
+
+/*
+=item i_test_format_probe(io_glue *data, int length)
+
+Cleans up the write buffer.
+
+Will flush any left-over data if I<flush> is non-zero.
+
+Returns non-zero if flush is zero or if info->cb() returns non-zero.
+
+Return zero only if flush is non-zero and info->cb() returns zero.
+ie. if it fails.
+
+=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
 
+=head1 AUTHOR
+
+Arnar M. Hrafnkelsson <addi@umich.edu>
+
+Tony Cook <tony@develop-help.com>
+
 =head1 SEE ALSO
 
 L<Imager>, L<gif.c>