]> git.imager.perl.org - imager.git/blobdiff - filters.im
freetype-config might not be available, allow pkg-config to work
[imager.git] / filters.im
index 06ac6a1ff5e2a064849f54cccc542caccf329147..7c23a5a56ab0fa4d5779c9cb58d03aa22f286d59 100644 (file)
@@ -1,3 +1,4 @@
+#define IMAGER_NO_CONTEXT
 #include "imager.h"
 #include "imageri.h"
 #include <stdlib.h>
@@ -73,8 +74,9 @@ i_contrast(i_img *im, float intensity) {
   unsigned char ch;
   unsigned int new_color;
   i_color rcolor;
+  dIMCTXim(im);
   
-  mm_log((1,"i_contrast(im %p, intensity %f)\n", im, intensity));
+  im_log((aIMCTX, 1,"i_contrast(im %p, intensity %f)\n", im, intensity));
   
   if(intensity < 0) return;
   
@@ -100,8 +102,9 @@ s_hardinvert_low(i_img *im, int all) {
   i_img_dim x, y;
   int ch;
   int invert_channels = all ? im->channels : i_img_color_channels(im);
+  dIMCTXim(im);
 
-  mm_log((1,"i_hardinvert(im %p)\n", im));
+  im_log((aIMCTX,1,"i_hardinvert)low(im %p, all %d)\n", im, all));
   
 #code im->bits <= 8  
   IM_COLOR *row, *entry;
@@ -184,8 +187,9 @@ i_noise(i_img *im, float amount, unsigned char type) {
   float damount = amount * 2;
   i_color rcolor;
   int color_inc = 0;
+  dIMCTXim(im);
   
-  mm_log((1,"i_noise(im %p, intensity %.2f\n", im, amount));
+  im_log((aIMCTX, 1,"i_noise(im %p, intensity %.2f\n", im, amount));
   
   if(amount < 0) return;
   
@@ -245,15 +249,15 @@ i_bumpmap(i_img *im, i_img *bump, int channel, i_img_dim light_x, i_img_dim ligh
   double aX, aY, aL;
   double fZ;
   unsigned char px1, px2, py1, py2;
-  
+  dIMCTXim(im);
   i_img new_im;
 
-  mm_log((1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
+  im_log((aIMCTX, 1, "i_bumpmap(im %p, add_im %p, channel %d, light(" i_DFp "), st %" i_DF ")\n",
          im, bump, channel, i_DFcp(light_x, light_y), i_DFc(st)));
 
 
   if(channel >= bump->channels) {
-    mm_log((1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
+    im_log((aIMCTX, 1, "i_bumpmap: channel = %d while bump image only has %d channels\n", channel, bump->channels));
     return;
   }
 
@@ -410,7 +414,6 @@ i_bumpmap_complex(i_img *im,
                  i_color *Is) {
   i_img new_im;
   
-  int inflight;
   i_img_dim x, y;
   int ch;
   i_img_dim mx, Mx, my, My;
@@ -427,12 +430,14 @@ i_bumpmap_complex(i_img *im,
   fvec R;         /* Reflection vector    */
   fvec V;         /* Vision vector        */
 
-  mm_log((1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp 
+  dIMCTXim(im);
+
+  im_log((aIMCTX, 1, "i_bumpmap_complex(im %p, bump %p, channel %d, t(" i_DFp 
          "), Lx %.2f, Ly %.2f, Lz %.2f, cd %.2f, cs %.2f, n %.2f, Ia %p, Il %p, Is %p)\n",
          im, bump, channel, i_DFcp(tx, ty), Lx, Ly, Lz, cd, cs, n, Ia, Il, Is));
   
   if (channel >= bump->channels) {
-    mm_log((1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
+    im_log((aIMCTX, 1, "i_bumpmap_complex: channel = %d while bump image only has %d channels\n", channel, bump->channels));
     return;
   }
 
@@ -456,7 +461,6 @@ i_bumpmap_complex(i_img *im,
     L.z = -Lz;
     normalize(&L);
   } else {      /* Light is the position of the light source */
-    inflight = 0;
     L.x = -0.2;
     L.y = -0.4;
     L.z =  1;
@@ -644,6 +648,102 @@ i_watermark(i_img *im, i_img *wmark, i_img_dim tx, i_img_dim ty, int pixdiff) {
   }
 }
 
+/*
+=item i_autolevels_mono(im, lsat, usat)
+
+Do autolevels, but monochromatically.
+
+=cut
+*/
+
+void
+i_autolevels_mono(i_img *im, float lsat, float usat) {
+  i_color val;
+  i_img_dim i, x, y, hist[256];
+  i_img_dim sum_lum, min_lum, max_lum;
+  i_img_dim upper_accum, lower_accum;
+  i_color *row;
+  dIMCTXim(im);
+  int adapt_channels = im->channels == 4 ? 2 : 1;
+  int color_channels = i_img_color_channels(im);
+  i_img_dim color_samples = im->xsize * color_channels;
+  
+
+  im_log((aIMCTX, 1,"i_autolevels_mono(im %p, lsat %f,usat %f)\n", im, lsat,usat));
+
+  /* build the histogram in 8-bits, unless the image has a very small
+     range it should make little difference to the result */
+  sum_lum = 0;
+  for (i = 0; i < 256; i++)
+    hist[i] = 0;
+
+  row = mymalloc(im->xsize * sizeof(i_color));
+  /* create histogram for each channel */
+  for (y = 0; y < im->ysize; y++) {
+    i_color *p = row;
+    i_glin(im, 0, im->xsize, y, row);
+    if (im->channels > 2)
+      i_adapt_colors(adapt_channels, im->channels, row, im->xsize);
+    for (x = 0; x < im->xsize; x++) {
+      hist[p->channel[0]]++;
+      ++p;
+    }
+  }
+  myfree(row);
+
+  for(i = 0; i < 256; i++) {
+    sum_lum += hist[i];
+  }
+  
+  min_lum = 0;
+  lower_accum = 0;
+  for (i = 0; i < 256; ++i) {
+    if (lower_accum < sum_lum * lsat)
+      min_lum = i;
+    lower_accum += hist[i];
+  }
+
+  max_lum = 255;
+  upper_accum = 0;
+  for(i = 255; i >= 0; i--) {
+    if (upper_accum < sum_lum * usat)
+      max_lum = i;
+    upper_accum  += hist[i];
+  }
+
+#code im->bits <= 8
+  IM_SAMPLE_T *srow = mymalloc(color_samples * sizeof(IM_SAMPLE_T));
+#ifdef IM_EIGHT_BIT
+  IM_WORK_T low = min_lum;
+  i_sample_t lookup[256];
+#else
+  IM_WORK_T low = min_lum / 255.0 * IM_SAMPLE_MAX;
+#endif
+  double scale = 255.0 / (max_lum - min_lum);
+
+#ifdef IM_EIGHT_BIT
+  for (i = 0; i < 256; ++i) {
+    IM_WORK_T tmp = (i - low) * scale;
+    lookup[i] = IM_LIMIT(tmp);
+  }
+#endif
+
+  for(y = 0; y < im->ysize; y++) {
+    IM_GSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
+    for(i = 0; i < color_samples; ++i) {
+#ifdef IM_EIGHT_BIT
+      srow[i] = lookup[srow[i]];
+#else
+      IM_WORK_T tmp = (srow[i] - low) * scale;
+      srow[i] = IM_LIMIT(tmp);
+#endif
+    }
+    IM_PSAMP(im, 0, im->xsize, y, srow, NULL, color_channels);
+  }
+  myfree(srow);
+#/code
+}
+
 
 /*
 =item i_autolevels(im, lsat, usat, skew)
@@ -657,6 +757,9 @@ occur when changing the contrast.
   usat - fraction of pixels that will be truncated at the higher end of the spectrum
   skew - not used yet
 
+Note: this code calculates levels and adjusts each channel separately,
+which will typically cause a color shift.
+
 =cut
 */
 
@@ -668,8 +771,9 @@ i_autolevels(i_img *im, float lsat, float usat, float skew) {
   i_img_dim gsum, gmin, gmax;
   i_img_dim bsum, bmin, bmax;
   i_img_dim rcl, rcu, gcl, gcu, bcl, bcu;
+  dIMCTXim(im);
 
-  mm_log((1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
+  im_log((aIMCTX, 1,"i_autolevels(im %p, lsat %f,usat %f,skew %f)\n", im, lsat,usat,skew));
 
   rsum=gsum=bsum=0;
   for(i=0;i<256;i++) rhist[i]=ghist[i]=bhist[i] = 0;
@@ -924,11 +1028,12 @@ i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int d
   size_t bytes;
 
   double *fdist;
+  dIMCTXim(im);
 
-  mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
+  im_log((aIMCTX, 1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
   
   for(p = 0; p<num; p++) {
-    mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
+    im_log((aIMCTX,1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
     ICL_info(&ival[p]);
   }
 
@@ -964,7 +1069,7 @@ i_gradgen(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *ival, int d
        fdist[p]  = i_max(xd*xd, yd*yd); /* manhattan distance */
        break;
       default:
-       i_fatal(3,"i_gradgen: Unknown distance measure\n");
+       im_fatal(aIMCTX, 3,"i_gradgen: Unknown distance measure\n");
       }
       cs += fdist[p];
     }
@@ -991,11 +1096,12 @@ i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *i
   i_img_dim x, y;
   i_img_dim xsize    = im->xsize;
   i_img_dim ysize    = im->ysize;
+  dIMCTXim(im);
 
-  mm_log((1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
+  im_log((aIMCTX,1,"i_gradgen(im %p, num %d, xo %p, yo %p, ival %p, dmeasure %d)\n", im, num, xo, yo, ival, dmeasure));
   
   for(p = 0; p<num; p++) {
-    mm_log((1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
+    im_log((aIMCTX, 1,"i_gradgen: p%d(" i_DFp ")\n", p, i_DFcp(xo[p], yo[p])));
     ICL_info(&ival[p]);
   }
 
@@ -1018,7 +1124,7 @@ i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *i
       mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
       break;
     default:
-      i_fatal(3,"i_nearest_color: Unknown distance measure\n");
+      im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
     }
 
     for(p = 1; p<num; p++) {
@@ -1035,7 +1141,7 @@ i_nearest_color_foo(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *i
        curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
        break;
       default:
-       i_fatal(3,"i_nearest_color: Unknown distance measure\n");
+       im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
       }
       if (curdist < mindist) {
        mindist = curdist;
@@ -1125,8 +1231,9 @@ i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval,
   i_img_dim ysize    = im->ysize;
   int *cmatch;
   size_t ival_bytes, tval_bytes;
+  dIMCTXim(im);
 
-  mm_log((1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
+  im_log((aIMCTX, 1,"i_nearest_color(im %p, num %d, xo %p, yo %p, oval %p, dmeasure %d)\n", im, num, xo, yo, oval, dmeasure));
 
   i_clear_error();
 
@@ -1179,7 +1286,7 @@ i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval,
       mindist = i_max(xd*xd, yd*yd); /* manhattan distance */
       break;
     default:
-      i_fatal(3,"i_nearest_color: Unknown distance measure\n");
+      im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
     }
     
     for(p = 1; p<num; p++) {
@@ -1196,7 +1303,7 @@ i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval,
        curdist = i_max(xd*xd, yd*yd); /* manhattan distance */
        break;
       default:
-       i_fatal(3,"i_nearest_color: Unknown distance measure\n");
+       im_fatal(aIMCTX, 3,"i_nearest_color: Unknown distance measure\n");
       }
       if (curdist < mindist) {
        mindist = curdist;
@@ -1226,6 +1333,10 @@ i_nearest_color(i_img *im, int num, i_img_dim *xo, i_img_dim *yo, i_color *oval,
 
   i_nearest_color_foo(im, num, xo, yo, ival, dmeasure);
 
+  myfree(cmatch);
+  myfree(ival);
+  myfree(tval);
+
   return 1;
 }
 
@@ -1320,6 +1431,7 @@ i_diff_image(i_img *im1, i_img *im2, double mindist) {
   i_img *out;
   int outchans, diffchans;
   i_img_dim xsize, ysize;
+  dIMCTXim(im1);
 
   i_clear_error();
   if (im1->channels != im2->channels) {
@@ -1639,9 +1751,9 @@ i_fountain(i_img *im, double xa, double ya, double xb, double yb,
   i_fcolor *line = NULL;
   i_fcolor *work = NULL;
   size_t line_bytes;
-  i_fountain_seg *my_segs;
   i_fill_combine_f combine_func = NULL;
   i_fill_combinef_f combinef_func = NULL;
+  dIMCTXim(im);
 
   i_clear_error();
 
@@ -1656,12 +1768,12 @@ i_fountain(i_img *im, double xa, double ya, double xb, double yb,
   line = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
 
   i_get_combine(combine, &combine_func, &combinef_func);
-  if (combinef_func)
+  if (combinef_func) {
     work = mymalloc(line_bytes); /* checked 17feb2005 tonyc */
+  }
 
   fount_init_state(&state, xa, ya, xb, yb, type, repeat, combine, 
                    super_sample, ssample_param, count, segs);
-  my_segs = state.segs;
 
   for (y = 0; y < im->ysize; ++y) {
     i_glinf(im, 0, im->xsize, y, line);
@@ -1673,18 +1785,18 @@ i_fountain(i_img *im, double xa, double ya, double xb, double yb,
       else
         got_one = state.ssfunc(&c, x, y, &state);
       if (got_one) {
-        if (combine)
+        if (combinef_func)
           work[x] = c;
         else 
           line[x] = c;
       }
     }
-    if (combine)
+    if (combinef_func)
       combinef_func(line, work, im->channels, im->xsize);
     i_plinf(im, 0, im->xsize, y, line);
   }
   fount_finish_state(&state);
-  if (work) myfree(work);
+  myfree(work);
   myfree(line);
 
   return 1;
@@ -1860,11 +1972,13 @@ fount_init_state(struct fount_state *state, double xa, double ya,
   case i_fts_random:
   case i_fts_circle:
     ssample_param = floor(0.5+ssample_param);
-    bytes = sizeof(i_fcolor) * ssample_param;
-    if (bytes / sizeof(i_fcolor) == ssample_param) {
-      state->ssample_data = mymalloc(sizeof(i_fcolor) * ssample_param);
+    if (im_size_t_max / sizeof(i_fcolor) > ssample_param) {
+      bytes = sizeof(i_fcolor) * ssample_param;
+      state->ssample_data = mymalloc(bytes);
     }
     else {
+      dIMCTX;
+      im_log((aIMCTX, 1,"size_t overflow calculating super-sample array size for random or circl"));
       super_sample = i_fts_none;
     }
     break;
@@ -2346,8 +2460,9 @@ fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
       got_one = f->state.ssfunc(&c, x, y, &f->state);
     else
       got_one = fount_getat(&c, x, y, &f->state);
-    
-    *data++ = c;
+
+    if (got_one)
+      *data++ = c;
     
     ++x;
   }