add new comparison method rgb_difference that resembles arithmetical difference per...
[imager.git] / render.im
index 57d2804..46211d0 100644 (file)
--- a/render.im
+++ b/render.im
@@ -5,7 +5,7 @@ Render utilities
 
 #define RENDER_MAGIC 0x765AE
 
-typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
+typedef void (*render_color_f)(i_render *, i_img_dim, i_img_dim, i_img_dim, unsigned char const *src, i_color const *color);
 
 #define i_has_alpha(channels) ((channels) == 2 || (channels) == 4)
 
@@ -13,8 +13,8 @@ typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *s
 
 #code
 
-static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
-static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
+static void IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
+static void IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
 
 static render_color_f IM_SUFFIX(render_color_tab)[] =
   {
@@ -25,18 +25,51 @@ static render_color_f IM_SUFFIX(render_color_tab)[] =
     IM_SUFFIX(render_color_alpha),
   };
 
-static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
-static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
+static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 /* the copy variant copies the source alpha to the the output alpha channel */
-static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 
-static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
-static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
+static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 
 #/code
 
+/* 
+=item i_render_new(im, width)
+=category Blit tools
+
+Allocate a new C<i_render> object and initialize it.
+
+=cut
+*/
+
+i_render *
+i_render_new(i_img *im, i_img_dim width) {
+  i_render *r = mymalloc(sizeof(i_render));
+
+  i_render_init(r, im, width);
+
+  return r;
+}
+
+/*
+=item i_render_delete(r)
+=category Blit tools
+
+Release an C<i_render> object.
+
+=cut
+*/
+
+void
+i_render_delete(i_render *r) {
+  i_render_done(r);
+  myfree(r);
+}
+
 void
-i_render_init(i_render *r, i_img *im, int width) {
+i_render_init(i_render *r, i_img *im, i_img_dim width) {
   r->magic = RENDER_MAGIC;
   r->im = im;
   r->line_width = width;
@@ -61,9 +94,9 @@ i_render_done(i_render *r) {
 }
 
 static void
-alloc_line(i_render *r, int width, int eight_bit) {
+alloc_line(i_render *r, i_img_dim width, i_img_dim eight_bit) {
   if (width > r->line_width) {
-    int new_width = r->line_width * 2;
+    i_img_dim new_width = r->line_width * 2;
     if (new_width < width)
       new_width = width;
 
@@ -111,9 +144,9 @@ alloc_line(i_render *r, int width, int eight_bit) {
 }
 
 static void
-alloc_fill_line(i_render *r, int width, int eight_bit) {
+alloc_fill_line(i_render *r, i_img_dim width, int eight_bit) {
   if (width > r->fill_width) {
-    int new_width = r->fill_width * 2;
+    i_img_dim new_width = r->fill_width * 2;
     if (new_width < width)
       new_width = width;
 
@@ -160,9 +193,21 @@ alloc_fill_line(i_render *r, int width, int eight_bit) {
   }
 }
 
+/*
+=item i_render_color(r, x, y, width, source, color)
+=category Blit tools
+
+Render the given color with the coverage specified by C<source[0]> to
+C<source[width-1]>.
+
+Renders in normal combine mode.
+
+=cut
+*/
+
 void
-i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
-               i_color const *color) {
+i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              unsigned char const *src, i_color const *color) {
   i_img *im = r->im;
   if (y < 0 || y >= im->ysize)
     return;
@@ -189,39 +234,7 @@ i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
   if (!width)
     return;
 
-#if 0
-  /* make sure our line buffer is big enough */
-  if (width > r->width) {
-    int new_width = r->width * 2;
-    if (new_width < width)
-      new_width = width;
-
-    if (r->im->bits <= 8) {
-      if (r->line_8)
-       r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
-      else
-       r->line_8 = mymalloc(sizeof(i_color) * new_width);
-      if (r->line_double) {
-       myfree(r->line_double);
-       r->line_double = NULL;
-      }
-    }
-    else {
-      if (r->line_double)
-       r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
-      else
-       r->line_double = mymalloc(sizeof(i_fcolor) * new_width);
-      if (r->line_8) {
-       myfree(r->line_8);
-       r->line_double = NULL;
-      }
-    }
-
-    r->width = new_width;
-  }
-#else
   alloc_line(r, width, r->im->bits <= 8);
-#endif
 
 #code r->im->bits <= 8
   /*if (r->IM_SUFFIX(line) == NULL)
@@ -230,9 +243,19 @@ i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
 #/code
 }
 
+/*
+=item i_render_fill(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+*/
+
 void
-i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
-             i_fill_t *fill) {
+i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+             unsigned char const *src, i_fill_t *fill) {
   i_img *im = r->im;
   int fill_channels = im->channels;
   
@@ -266,56 +289,8 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
   if (!width)
     return;
 
-#if 0
-  if (r->im->bits <= 8 && fill->f_fill_with_color) {
-    if (!r->line_8)
-      r->line_8 = mymalloc(sizeof(i_color) * r->width);
-    if (!r->fill_line_8)
-      r->fill_line_8 = mymalloc(sizeof(i_color) * r->width);
-  }
-  else {
-    if (!r->line_double)
-      r->line_double = mymalloc(sizeof(i_fcolor) * r->width);
-    if (!r->fill_line_double)
-      r->fill_line_double = mymalloc(sizeof(i_fcolor) * r->width);
-  }
-
-  /* make sure our line buffer is big enough */
-  if (width > r->width) {
-    int new_width = r->width * 2;
-    if (new_width < width)
-      new_width = width;
-
-    if (r->im->bits <= 8 && fill->f_fill_with_color) {
-      r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
-      r->fill_line_8 = myrealloc(r->fill_line_8, sizeof(i_color) * new_width);
-      if (r->line_double) {
-       myfree(r->line_double);
-       r->line_double = NULL;
-      }
-      if (r->fill_line_double) {
-       myfree(r->fill_line_double);
-       r->fill_line_double = NULL;
-      }
-    }
-    else {
-      r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
-      r->fill_line_double = myrealloc(r->fill_line_double, sizeof(i_fcolor) * new_width);
-      if (r->line_8) {
-       myfree(r->line_8);
-       r->line_8 = NULL;
-      }
-      if (r->fill_line_8) {
-       myfree(r->fill_line_8);
-       r->fill_line_8 = NULL;
-      }
-    }
-    r->width = new_width;
-  }
-#else
   alloc_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL);
   alloc_fill_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL);
-#endif
 
 #code r->im->bits <= 8 && fill->f_fill_with_color
   if (IM_FILL_COMBINE(fill)) {
@@ -325,7 +300,7 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
     if (src) {
       unsigned char const *srcc = src;
       IM_COLOR *fillc = r->IM_SUFFIX(fill_line);
-      int work_width = width;
+      i_img_dim work_width = width;
       while (work_width) {
        if (*srcc == 0) {
          fillc->channel[fill_channels-1] = 0;
@@ -344,7 +319,7 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
   }
   else {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *srcc = r->IM_SUFFIX(fill_line);
       IM_COLOR *destc = r->IM_SUFFIX(line);
       int ch;
@@ -358,8 +333,8 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
        }
        else if (*src) {
          for (ch = 0; ch < im->channels; ++ch) {
-           IM_WORK_T work = (destc->channel[ch] * (IM_SAMPLE_MAX - *src)
-                             + srcc->channel[ch] * *src) / IM_SAMPLE_MAX;
+           IM_WORK_T work = (destc->channel[ch] * (255 - *src)
+                             + srcc->channel[ch] * *src) / 255.0;
            destc->channel[ch] = IM_LIMIT(work);
          }
        }
@@ -371,28 +346,53 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
       }
     }
     else { /* if (src) */
-      IM_FILL_FILLER(fill)(fill, x, y, width, r->im->channels, r->IM_SUFFIX(line));
+      IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(line));
     }
   }
   IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
 #/code
 }
 
+#if 0
+
+/* for debuggin */
+
 static void
-dump_src(const char *note, unsigned char const *src, int width) {
-  int i;
-  printf("%s - %p/%d\n", note, src, width);
+dump_src(const char *note, unsigned char const *src, i_img_dim width) {
+  i_img_dim i;
+  printf("%s - %p/%" i_DF "\n", note, src, i_DFc(width));
   for (i = 0; i < width; ++i) {
     printf("%02x ", src[i]);
   }
   putchar('\n');
 }
 
+#endif
+
 #code
 
+/*
+=item i_render_line(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+
+=item i_render_linef(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+*/
+
 void
-IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
-             IM_COLOR *line, IM_FILL_COMBINE_F combine) {
+IM_RENDER_LINE(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              const IM_SAMPLE_T *src, IM_COLOR *line,
+              IM_FILL_COMBINE_F combine) {
   i_img *im = r->im;
   int src_chans = im->channels;
 
@@ -419,7 +419,7 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
 
   if (combine) {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *linep = line;
       const IM_SAMPLE_T *srcp = src;
       int alpha_chan = src_chans - 1;
@@ -444,7 +444,7 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
   }
   else {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *srcc = line;
       IM_COLOR *destc = r->IM_SUFFIX(line);
 
@@ -478,12 +478,14 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
 
 static
 void
-IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, 
-                unsigned char const *src, i_color const *color) {
+IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y,
+                          i_img_dim width, unsigned char const *src,
+                          i_color const *color) {
   i_img *im = r->im;
   IM_COLOR *linep = r->IM_SUFFIX(line);
   int ch, channels = im->channels;
-  int fetch_offset;
+  i_img_dim fetch_offset;
+  int color_alpha = color->channel[im->channels];
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -497,17 +499,19 @@ IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
 #endif
  
   fetch_offset = 0;
-  while (fetch_offset < width && *src == 0xFF) {
-    *linep++ = STORE_COLOR;
-    ++src;
-    ++fetch_offset;
+  if (color_alpha == 0xFF) {
+    while (fetch_offset < width && *src == 0xFF) {
+      *linep++ = STORE_COLOR;
+      ++src;
+      ++fetch_offset;
+    }
   }
   IM_GLIN(im, x+fetch_offset, x+width, y, linep);
   while (fetch_offset < width) {
 #ifdef IM_EIGHT_BIT
-    IM_WORK_T alpha = *src++;
+    IM_WORK_T alpha = *src++ * color_alpha / 255;
 #else
-    IM_WORK_T alpha = *src++ / 255.0;
+    IM_WORK_T alpha = *src++ * color_alpha / (255.0 * 255.0);
 #endif
     if (alpha == IM_SAMPLE_MAX)
       *linep = STORE_COLOR;
@@ -525,12 +529,14 @@ IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
 
 static
 void
-IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, 
-                unsigned char const *src, i_color const *color) {
+IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y,
+                             i_img_dim width, unsigned char const *src,
+                             i_color const *color) {
   IM_COLOR *linep = r->IM_SUFFIX(line);
   int ch;
   int alpha_channel = r->im->channels - 1;
-  int fetch_offset;
+  i_img_dim fetch_offset;
+  int color_alpha = color->channel[alpha_channel];
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -544,17 +550,19 @@ IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
 #endif
 
   fetch_offset = 0;
-  while (fetch_offset < width && *src == 0xFF) {
-    *linep++ = STORE_COLOR;
-    ++src;
-    ++fetch_offset;
+  if (color->channel[alpha_channel] == 0xFF) {
+    while (fetch_offset < width && *src == 0xFF) {
+      *linep++ = STORE_COLOR;
+      ++src;
+      ++fetch_offset;
+    }
   }
   IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
   while (fetch_offset < width) {
 #ifdef IM_EIGHT_BIT
-    IM_WORK_T src_alpha = *src++;
+    IM_WORK_T src_alpha = *src++ * color_alpha / 255;
 #else
-    IM_WORK_T src_alpha = *src++ / 255.0;
+    IM_WORK_T src_alpha = *src++ * color_alpha / (255.0 * 255.0);
 #endif
     if (src_alpha == IM_SAMPLE_MAX)
       *linep = STORE_COLOR;
@@ -585,7 +593,7 @@ IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
 
 static void
 IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, 
-                             int channels, int count) {
+                             int channels, i_img_dim count) {
   int ch;
   int alpha_channel = channels - 1;
   
@@ -622,7 +630,7 @@ IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in,
 
 static void
 IM_SUFFIX(combine_line_noalpha)
-     (IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+     (IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   int ch;
 
   while (count) {
@@ -657,7 +665,7 @@ IM_SUFFIX(combine_line_noalpha)
 
 static void
 IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, 
-                                  int channels, int count) {
+                                  int channels, i_img_dim count) {
   int ch;
   int alpha_channel = channels - 1;
   
@@ -685,7 +693,7 @@ IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in,
 }
 
 static void
-IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   if (channels == 2 || channels == 4)
     IM_SUFFIX(combine_line_alpha)(out, in, channels, count);
   else
@@ -693,25 +701,25 @@ IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int cou
 }
 
 static void
-IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   if (channels == 2 || channels == 4)
     IM_SUFFIX(combine_line_alpha_na)(out, in, channels, count);
   else
     IM_SUFFIX(combine_line_noalpha)(out, in, channels, count);
 }
 
-static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, int);
+static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
 
 static const IM_FILL_COMBINE_F IM_SUFFIX(combines)[] =
 {
@@ -740,7 +748,7 @@ static const IM_FILL_COMBINE_F IM_SUFFIX(combines)[] =
 
 void i_get_combine(int combine, i_fill_combine_f *color_func, 
                    i_fill_combinef_f *fcolor_func) {
-  if (combine < 0 || combine > sizeof(combines_8) / sizeof(*combines_8))
+  if (combine < 0 || combine >= sizeof(combines_8) / sizeof(*combines_8))
     combine = 0;
 
   *color_func = combines_8[combine];
@@ -768,7 +776,7 @@ void i_get_combine(int combine, i_fill_combine_f *color_func,
 
 
 static void 
-IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   IM_SUFFIX(combine_line)(out, in, channels, count);
 }
 
@@ -782,11 +790,11 @@ When Da=1
 Dc' = Sc.Sa.Dc + Dc.(1 - Sa)
  */
 static void
-IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -831,7 +839,7 @@ IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int color_channels = i_color_channels(channels);
   int ch;
 
@@ -868,10 +876,10 @@ Da'  = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
 */
 
 static void
-IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   int color_channels = i_color_channels(channels);
-  int work_count = count;
+  i_img_dim work_count = count;
   IM_COLOR *inp = in;
   IM_COLOR *outp = out;
 
@@ -923,11 +931,11 @@ IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
    channel to apply that to the target.
  */
 static void
-IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -981,11 +989,11 @@ Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
 Da'  = Sa + Da - Sa.Da 
 */
 static void
-IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -1049,11 +1057,11 @@ IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
  */
 static void 
 IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels, 
-                         int count) {
+                         i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -1104,11 +1112,11 @@ IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels,
 }
 
 static void 
-IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -1167,11 +1175,11 @@ IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, int count)
 #endif
 
 static void 
-IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     if (i_has_alpha(channels)) {
       while (work_count--) {
@@ -1228,11 +1236,11 @@ IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void
-IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;
@@ -1251,11 +1259,11 @@ IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;
@@ -1276,11 +1284,11 @@ IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;