]> git.imager.perl.org - imager.git/blobdiff - scale.im
various minor documentation updates and fixes
[imager.git] / scale.im
index 7f8ed769d0c7afa111a6b7ee3cd3449848918191..36ed2a56bc26ac2b78437207f2086080c4458ea4 100644 (file)
--- a/scale.im
+++ b/scale.im
@@ -1,4 +1,5 @@
 #include "imager.h"
+#include "imageri.h"
 
 /*
  * i_scale_mixing() is based on code contained in pnmscale.c, part of
@@ -51,7 +52,7 @@ i_img *
 i_scale_mixing(i_img *src, int x_out, int y_out) {
   i_img *result;
   i_fcolor *accum_row = NULL;
-  int y;
+  int x, y, ch;
   int accum_row_bytes;
   double rowsleft, fracrowtofill;
   int rowsread;
@@ -125,6 +126,15 @@ i_scale_mixing(i_img *src, int x_out, int y_out) {
 #else
       IM_GLIN(src, 0, src->xsize, y, accum_row);
 #endif
+      /* alpha adjust if needed */
+      if (src->channels == 2 || src->channels == 4) {
+       for (x = 0; x < src->xsize; ++x) {
+         for (ch = 0; ch < src->channels-1; ++ch) {
+           accum_row[x].channel[ch] *=
+             accum_row[x].channel[src->channels-1] / IM_SAMPLE_MAX;
+         }
+       }
+      }
     }
     else {
       fracrowtofill = 1.0;
@@ -158,9 +168,35 @@ i_scale_mixing(i_img *src, int x_out, int y_out) {
 #if IM_EIGHT_BIT
       int x, ch;
       /* no need to scale, but we need to convert it */
-      for (x = 0; x < x_out; ++x) {
-        for (ch = 0; ch < result->channels; ++ch)
-          xscale_row[x].channel[ch] = accum_row[x].channel[ch];
+      if (result->channels == 2 || result->channels == 4) {
+       int alpha_chan = result->channels - 1;
+       for (x = 0; x < x_out; ++x) {
+         double alpha = accum_row[x].channel[alpha_chan] / IM_SAMPLE_MAX;
+         if (alpha) {
+           for (ch = 0; ch < alpha_chan; ++ch) {
+             int val = accum_row[x].channel[ch] / alpha + 0.5;
+             xscale_row[x].channel[ch] = IM_LIMIT(val);
+           }
+         }
+         else {
+           /* rather than leaving any color data as whatever was
+              originally in the buffer, set it to black.  This isn't
+              any more correct, but it gives us more compressible
+              image data.
+              RT #32324
+           */
+           for (ch = 0; ch < alpha_chan; ++ch) {
+             xscale_row[x].channel[ch] = 0;
+           }
+         }
+         xscale_row[x].channel[alpha_chan] = IM_LIMIT(accum_row[x].channel[alpha_chan]+0.5);
+       }
+      }
+      else {
+       for (x = 0; x < x_out; ++x) {
+         for (ch = 0; ch < result->channels; ++ch)
+           xscale_row[x].channel[ch] = IM_LIMIT(accum_row[x].channel[ch]+0.5);
+       }
       }
       IM_PLIN(result, 0, x_out, y, xscale_row);
 #else
@@ -205,9 +241,19 @@ IM_SUFFIX(accum_output_row)(i_fcolor *accum, double fraction, IM_COLOR const *in
 
   /* it's tempting to change this into a pointer iteration loop but
      modern CPUs do the indexing as part of the instruction */
-  for (x = 0; x < width; ++x) {
-    for (ch = 0; ch < channels; ++ch) {
-      accum[x].channel[ch] += in[x].channel[ch] * fraction;
+  if (channels == 2 || channels == 4) {
+    for (x = 0; x < width; ++x) {
+      for (ch = 0; ch < channels-1; ++ch) {
+       accum[x].channel[ch] += in[x].channel[ch] * fraction * in[x].channel[channels-1] / IM_SAMPLE_MAX;
+      }
+      accum[x].channel[channels-1] += in[x].channel[channels-1] * fraction;
+    }
+  }
+  else {
+    for (x = 0; x < width; ++x) {
+      for (ch = 0; ch < channels; ++ch) {
+       accum[x].channel[ch] += in[x].channel[ch] * fraction;
+      }
     }
   }
 }
@@ -231,10 +277,31 @@ IM_SUFFIX(horizontal_scale)(IM_COLOR *out, int out_width,
       for (ch = 0; ch < channels; ++ch)
        accum[ch] += frac_col_to_fill * in[in_x].channel[ch];
 
-      for (ch = 0; ch < channels; ++ch) {
-       out[out_x].channel[ch] = accum[ch];
-       accum[ch] = 0;
+      if (channels == 2 || channels == 4) {
+       int alpha_chan = channels - 1;
+       double alpha = accum[alpha_chan] / IM_SAMPLE_MAX;
+       if (alpha) {
+         for (ch = 0; ch < alpha_chan; ++ch) {
+           IM_WORK_T val = IM_ROUND(accum[ch] / alpha);
+           out[out_x].channel[ch] = IM_LIMIT(val);
+         }
+       }
+       else {
+         for (ch = 0; ch < alpha_chan; ++ch) {
+           /* See RT #32324 (and mention above) */
+           out[out_x].channel[ch] = 0;
+         }
+       }
+       out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan]));
       }
+      else {
+       for (ch = 0; ch < channels; ++ch) {
+         IM_WORK_T val = IM_ROUND(accum[ch]);
+         out[out_x].channel[ch] = IM_LIMIT(val);
+       }
+      }
+      for (ch = 0; ch < channels; ++ch)
+       accum[ch] = 0;
       frac_col_left -= frac_col_to_fill;
       frac_col_to_fill = 1.0;
       ++out_x;
@@ -255,7 +322,29 @@ IM_SUFFIX(horizontal_scale)(IM_COLOR *out, int out_width,
   if (out_x < out_width) {
     for (ch = 0; ch < channels; ++ch) {
       accum[ch] += frac_col_to_fill * in[in_width-1].channel[ch];
-      out[out_x].channel[ch] = accum[ch];
+    }
+    if (channels == 2 || channels == 4) {
+      int alpha_chan = channels - 1;
+      double alpha = accum[alpha_chan] / IM_SAMPLE_MAX;
+      if (alpha) {
+       for (ch = 0; ch < alpha_chan; ++ch) {
+         IM_WORK_T val = IM_ROUND(accum[ch] / alpha);
+         out[out_x].channel[ch] = IM_LIMIT(val);
+       }
+      }
+      else {
+       for (ch = 0; ch < alpha_chan; ++ch) {
+         /* See RT #32324 (and mention above) */
+         out[out_x].channel[ch] = 0;
+       }
+      }
+      out[out_x].channel[alpha_chan] = IM_LIMIT(IM_ROUND(accum[alpha_chan]));
+    }
+    else {
+      for (ch = 0; ch < channels; ++ch) {
+       IM_WORK_T val = IM_ROUND(accum[ch]);
+       out[out_x].channel[ch] = IM_LIMIT(val);
+      }
     }
   }
 }