]> git.imager.perl.org - imager.git/blobdiff - fills.c
missed a PERL_NO_GET_CONTEXT
[imager.git] / fills.c
diff --git a/fills.c b/fills.c
index 55139ed092eceac57d01c73aa56822bc623de318..5ca4293473184e3f6bce8b06b30bc1180bab18a6 100644 (file)
--- a/fills.c
+++ b/fills.c
@@ -17,6 +17,7 @@ fills.c - implements the basic general fills
   fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
   fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
   fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
+  fill = i_new_fill_opacity(fill, alpha_mult);
   i_fill_destroy(fill);
 
 =head1 DESCRIPTION
@@ -180,7 +181,7 @@ static i_fill_solid_t base_solid_fill =
 
 /*
 =item i_fill_destroy(fill)
-
+=order 90
 =category Fills
 =synopsis i_fill_destroy(fill);
 
@@ -411,21 +412,23 @@ i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const
                 int dx, int dy);
 
 /*
-=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
+=item i_new_fill_hatch(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
 
 =category Fills
 =synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
 
-Creates a new hatched fill with the fg color used for the 1 bits in
-the hatch and bg for the 0 bits.  If combine is non-zero alpha values
-will be combined.
+Creates a new hatched fill with the C<fg> color used for the 1 bits in
+the hatch and C<bg> for the 0 bits.  If C<combine> is non-zero alpha
+values will be combined.
 
-If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
+If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
 hash definition, with the high-bits to the left.
 
-If cust_hatch is NULL then one of the standard hatches is used.
+If C<cust_hatch> is NULL then one of the standard hatches is used.
 
-(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
+(C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
+adjoining areas out of alignment, or to align the origin of a hatch
+with the the side of a filled area.
 
 =cut
 */
@@ -437,21 +440,23 @@ i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
 }
 
 /*
-=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
+=item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
 
 =category Fills
 =synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
 
-Creates a new hatched fill with the fg color used for the 1 bits in
-the hatch and bg for the 0 bits.  If combine is non-zero alpha values
-will be combined.
+Creates a new hatched fill with the C<fg> color used for the 1 bits in
+the hatch and C<bg> for the 0 bits.  If C<combine> is non-zero alpha
+values will be combined.
 
-If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
+If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
 hash definition, with the high-bits to the left.
 
-If cust_hatch is NULL then one of the standard hatches is used.
+If C<cust_hatch> is NULL then one of the standard hatches is used.
 
-(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
+(C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
+adjoining areas out of alignment, or to align the origin of a hatch
+with the the side of a filled area.
 
 =cut
 */
@@ -485,7 +490,7 @@ image_fill_proto =
   };
 
 /*
-=item i_new_fill_image(im, matrix, xoff, yoff, combine)
+=item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
 
 =category Fills
 =synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
@@ -494,7 +499,7 @@ Create an image based fill.
 
 matrix is an array of 9 doubles representing a transformation matrix.
 
-xoff and yoff are the offset into the image to start filling from.
+C<xoff> and C<yoff> are the offset into the image to start filling from.
 
 =cut
 */
@@ -528,6 +533,38 @@ i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combin
   return &fill->base;
 }
 
+static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
+                       i_color *data);
+static void fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
+                       i_fcolor *data);
+
+struct i_fill_opacity_t {
+  i_fill_t base;
+  i_fill_t *other_fill;
+  double alpha_mult;
+};
+
+static struct i_fill_opacity_t
+opacity_fill_proto =
+  {
+    fill_opacity,
+    fill_opacityf,
+    NULL
+  };
+
+i_fill_t *
+i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
+  struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
+  *fill = opacity_fill_proto;
+
+  fill->base.combine = base_fill->combine;
+  fill->base.combinef = base_fill->combinef;
+
+  fill->other_fill = base_fill;
+  fill->alpha_mult = alpha_mult;
+
+  return &fill->base;
+}
 
 #define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
 
@@ -650,12 +687,20 @@ static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
   int byte = f->hatch[(y + f->dy) & 7];
   int xpos = (x + f->dx) & 7;
   int mask = 128 >> xpos;
+  i_color fg = f->fg;
+  i_color bg = f->bg;
+  int want_channels = channels > 2 ? 4 : 2;
+
+  if (channels < 3) {
+    i_adapt_colors(2, 4, &fg, 1);
+    i_adapt_colors(2, 4, &bg, 1);
+  }
 
   while (width-- > 0) {
     if (byte & mask)
-      *data++ = f->fg;
+      *data++ = fg;
     else
-      *data++ = f->bg;
+      *data++ = bg;
     
     if ((mask >>= 1) == 0)
       mask = 128;
@@ -675,12 +720,19 @@ static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
   int byte = f->hatch[(y + f->dy) & 7];
   int xpos = (x + f->dx) & 7;
   int mask = 128 >> xpos;
+  i_fcolor fg = f->ffg;
+  i_fcolor bg = f->fbg;
+
+  if (channels < 3) {
+    i_adapt_fcolors(2, 4, &fg, 1);
+    i_adapt_fcolors(2, 4, &bg, 1);
+  }
   
   while (width-- > 0) {
     if (byte & mask)
-      *data++ = f->ffg;
+      *data++ = fg;
     else
-      *data++ = f->fbg;
+      *data++ = bg;
     
     if ((mask >>= 1) == 0)
       mask = 128;
@@ -741,6 +793,7 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
   int i = 0;
   i_color *out = data;
+  int want_channels = channels > 2 ? 4 : 2;
   
   if (f->has_matrix) {
     /* the hard way */
@@ -803,33 +856,12 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
       ++i;
     }
   }
-  if (f->src->channels == 3) {
-    /* just set the alpha */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = 255;
-      data++;
-    }
-  }
-  else if (f->src->channels == 2) {
-    /* copy the alpha to channel 3, duplicate the grey value */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = data->channel[1];
-      data->channel[1] = data->channel[2] = data->channel[0];
-      data++;
-    }
-  }
-  else if (f->src->channels == 1) {
-    /* set the alpha, duplicate grey */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = 255;
-      data->channel[1] = data->channel[2] = data->channel[0];
-      data++;
-    }
-  }
+  if (f->src->channels != want_channels)
+    i_adapt_colors(want_channels, f->src->channels, data, width);
 }
 
 /*
-=item fill_image(fill, x, y, width, channels, data, work)
+=item fill_imagef(fill, x, y, width, channels, data, work)
 
 =cut
 */
@@ -837,8 +869,10 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
                        i_fcolor *data) {
   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
   int i = 0;
+  int want_channels = channels > 2 ? 4 : 2;
   
   if (f->has_matrix) {
+    i_fcolor *work_data = data;
     /* the hard way */
     while (i < width) {
       double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
@@ -871,11 +905,12 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
         }
         c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
       }
-      *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
+      *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
       ++i;
     }
   }
   else {
+    i_fcolor *work_data = data;
     /* the easy way */
     /* this should be possible to optimize to use i_glin() */
     while (i < width) {
@@ -894,37 +929,55 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
       }
       rx -= ix * f->src->xsize;
       ry -= iy * f->src->ysize;
-      i_gpixf(f->src, rx, ry, data);
-      ++data;
+      i_gpixf(f->src, rx, ry, work_data);
+      ++work_data;
       ++i;
     }
   }
-  if (f->src->channels == 3) {
-    /* just set the alpha */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = 1.0;
-      data++;
-    }
-  }
-  else if (f->src->channels == 2) {
-    /* copy the alpha to channel 3, duplicate the grey value */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = data->channel[1];
-      data->channel[1] = data->channel[2] = data->channel[0];
-      data++;
-    }
+  if (f->src->channels != want_channels)
+    i_adapt_fcolors(want_channels, f->src->channels, data, width);
+}
+
+static void 
+fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
+            i_color *data) {
+  struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
+  int alpha_chan = channels > 2 ? 3 : 1;
+  i_color *datap = data;
+  
+  (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
+  while (width--) {
+    double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
+    if (new_alpha < 0) 
+      datap->channel[alpha_chan] = 0;
+    else if (new_alpha > 255)
+      datap->channel[alpha_chan] = 255;
+    else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
+
+    ++datap;
   }
-  else if (f->src->channels == 1) {
-    /* set the alpha, duplicate grey */
-    for (i = 0; i <  width; ++i) {
-      data->channel[3] = 1.0;
-      data->channel[1] = data->channel[2] = data->channel[0];
-      data++;
-    }
+}
+static void 
+fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
+           i_fcolor *data) {
+  struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
+  int alpha_chan = channels > 2 ? 3 : 1;
+  i_fcolor *datap = data;
+  
+  (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
+  
+  while (width--) {
+    double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
+    if (new_alpha < 0) 
+      datap->channel[alpha_chan] = 0;
+    else if (new_alpha > 1.0)
+      datap->channel[alpha_chan] = 1.0;
+    else datap->channel[alpha_chan] = new_alpha;
+
+    ++datap;
   }
 }
 
-
 /*
 =back