remove a pointless NULL check from i_flipxy()
[imager.git] / rotate.im
index e6d1d11..96981be 100644 (file)
--- a/rotate.im
+++ b/rotate.im
@@ -20,6 +20,8 @@ Other rotations will be added as tuits become available.
 #include "imageri.h"
 #include <math.h> /* for floor() */
 
+#define ROT_DEBUG(x)
+
 i_img *i_rotate90(i_img *src, int degrees) {
   i_img *targ;
   i_img_dim x, y;
@@ -128,10 +130,9 @@ static i_color interp_i_color(i_color before, i_color after, double pos,
   i_color out;
   int ch;
 
-  pos -= floor(pos);
   if (channels == 1 || channels == 3) {
     for (ch = 0; ch < channels; ++ch)
-      out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+      out.channel[ch] = ((1-pos) * before.channel[ch] + pos * after.channel[ch]) + 0.5;
   }
   else {
     int total_cover = (1-pos) * before.channel[channels-1]
@@ -145,11 +146,15 @@ static i_color interp_i_color(i_color before, i_color after, double pos,
 
       for (ch = 0; ch < channels-1; ++ch) {
        int out_level = ((1-pos) * before.channel[ch] * before_alpha + 
-                        pos * after.channel[ch] * after_alpha + 0.5) / total_alpha;
+                        pos * after.channel[ch] * after_alpha) / total_alpha + 0.5;
 
        out.channel[ch] = I_LIMIT_8(out_level);
       }
     }
+    else {
+      for (ch = 0; ch < channels-1; ++ch)
+       out.channel[ch] = 0;
+    }
 
     out.channel[channels-1] = total_cover;
   }
@@ -164,7 +169,6 @@ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
   i_fcolor out;
   int ch;
 
-  pos -= floor(pos);
   if (channels == 1 || channels == 3) {
     for (ch = 0; ch < channels; ++ch)
       out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
@@ -186,6 +190,10 @@ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
        out.channel[ch] = I_LIMIT_DOUBLE(out_level);
       }
     }
+    else {
+      for (ch = 0; ch < channels-1; ++ch)
+       out.channel[ch] = 0;
+    }
 
     out.channel[channels-1] = total_cover;
   }
@@ -205,7 +213,6 @@ i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const
 #code src->bits <= 8
     IM_COLOR *vals = mymalloc(xsize * sizeof(IM_COLOR));
     IM_COLOR back;
-    i_fsample_t fsamp;
 
 #ifdef IM_EIGHT_BIT
     if (backp) {
@@ -213,6 +220,7 @@ i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const
     }
     else if (fbackp) {
       for (ch = 0; ch < src->channels; ++ch) {
+       i_fsample_t fsamp;
        fsamp = fbackp->channel[ch];
        back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255;
       }
@@ -250,38 +258,50 @@ i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const
        if (fabs(sz) > 0.0000001 
            && sx >= -1 && sx < src->xsize
            && sy >= -1 && sy < src->ysize) {
-         
-         if (sx != (i_img_dim)sx) {
-           if (sy != (i_img_dim)sy) {
+         double fsx = floor(sx);
+         double fsy = floor(sy);
+         i_img_dim bx = fsx;
+         i_img_dim by = fsy;
+
+         ROT_DEBUG(fprintf(stderr, "map " i_DFp " to %g,%g\n", i_DFcp(x, y), sx, sy));
+         if (sx != fsx) {
+           double dx = sx - fsx;
+           if (sy != fsy) {
              IM_COLOR c[2][2]; 
              IM_COLOR ci2[2];
+             double dy = sy - fsy;
+             ROT_DEBUG(fprintf(stderr, " both non-int\n"));
              for (i = 0; i < 2; ++i)
                for (j = 0; j < 2; ++j)
-                 if (IM_GPIX(src, floor(sx)+i, floor(sy)+j, &c[j][i]))
+                 if (IM_GPIX(src, bx+i, by+j, &c[j][i]))
                    c[j][i] = back;
              for (j = 0; j < 2; ++j)
-               ci2[j] = interp_i_color(c[j][0], c[j][1], sx, src->channels);
-             vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels);
+               ci2[j] = interp_i_color(c[j][0], c[j][1], dx, src->channels);
+             vals[x] = interp_i_color(ci2[0], ci2[1], dy, src->channels);
            }
            else {
              IM_COLOR ci2[2];
+             ROT_DEBUG(fprintf(stderr, " y int, x non-int\n"));
              for (i = 0; i < 2; ++i)
-               if (IM_GPIX(src, floor(sx)+i, sy, ci2+i))
+               if (IM_GPIX(src, bx+i, sy, ci2+i))
                  ci2[i] = back;
-             vals[x] = interp_i_color(ci2[0], ci2[1], sx, src->channels);
+             vals[x] = interp_i_color(ci2[0], ci2[1], dx, src->channels);
            }
          }
          else {
-           if (sy != (i_img_dim)sy) {
+           if (sy != fsy) {
              IM_COLOR ci2[2];
+             double dy = sy - fsy;
+             ROT_DEBUG(fprintf(stderr, " x int, y non-int\n"));
              for (i = 0; i < 2; ++i)
-               if (IM_GPIX(src, sx, floor(sy)+i, ci2+i))
+               if (IM_GPIX(src, bx, by+i, ci2+i))
                  ci2[i] = back;
-             vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels);
+             vals[x] = interp_i_color(ci2[0], ci2[1], dy, src->channels);
            }
            else {
+             ROT_DEBUG(fprintf(stderr, " both int\n"));
              /* all the world's an integer */
-             if (IM_GPIX(src, sx, sy, vals+x))
+             if (IM_GPIX(src, bx, by, vals+x))
                vals[x] = back;
            }
          }
@@ -300,7 +320,6 @@ i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const
     /* don't interpolate for a palette based image */
     i_palidx *vals = mymalloc(xsize * sizeof(i_palidx));
     i_palidx back = 0;
-    i_color min;
     int minval = 256 * 4;
     i_img_dim ix, iy;
     i_color want_back;
@@ -331,7 +350,6 @@ i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const
       }
       if (tempval < minval) {
         back = i;
-        min = temp;
         minval = tempval;
       }
     }
@@ -393,6 +411,15 @@ i_matrix_mult(double *dest, const double *left, const double *right) {
   }
 }
 
+#define numfmt "%23g"
+
+ROT_DEBUG(static void dump_mat(const char *name, double *f) {
+  fprintf(stderr, "%s:\n  " numfmt " " numfmt " " numfmt "\n"
+         "  " numfmt " " numfmt " " numfmt "\n"
+         "  " numfmt " " numfmt " " numfmt "\n",
+         name, f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8]);
+  })
+
 i_img *i_rotate_exact_bg(i_img *src, double amount, 
                         const i_color *backp, const i_fcolor *fbackp) {
   double xlate1[9] = { 0 };
@@ -401,13 +428,17 @@ i_img *i_rotate_exact_bg(i_img *src, double amount,
   double temp[9], matrix[9];
   i_img_dim x1, x2, y1, y2, newxsize, newysize;
 
+  ROT_DEBUG(fprintf(stderr, "rotate angle %.20g\n", amount));
+
   /* first translate the centre of the image to (0,0) */
   xlate1[0] = 1;
-  xlate1[2] = src->xsize/2.0;
+  xlate1[2] = (src->xsize-1)/2.0;
   xlate1[4] = 1;
-  xlate1[5] = src->ysize/2.0;
+  xlate1[5] = (src->ysize-1)/2.0;
   xlate1[8] = 1;
 
+  ROT_DEBUG(dump_mat("xlate1", xlate1));
+
   /* rotate around (0.0) */
   rotate[0] = cos(amount);
   rotate[1] = sin(amount);
@@ -419,21 +450,31 @@ i_img *i_rotate_exact_bg(i_img *src, double amount,
   rotate[7] = 0;
   rotate[8] = 1;
 
-  x1 = ceil(i_abs(src->xsize * rotate[0] + src->ysize * rotate[1]));
-  x2 = ceil(i_abs(src->xsize * rotate[0] - src->ysize * rotate[1]));
-  y1 = ceil(i_abs(src->xsize * rotate[3] + src->ysize * rotate[4]));
-  y2 = ceil(i_abs(src->xsize * rotate[3] - src->ysize * rotate[4]));
+  ROT_DEBUG(dump_mat("rotate", rotate));
+
+  ROT_DEBUG(fprintf(stderr, "cos %g sin %g\n", rotate[0], rotate[1]));
+
+  x1 = ceil(fabs(src->xsize * rotate[0] + src->ysize * rotate[1]) - 0.0001);
+  x2 = ceil(fabs(src->xsize * rotate[0] - src->ysize * rotate[1]) - 0.0001);
+  y1 = ceil(fabs(src->xsize * rotate[3] + src->ysize * rotate[4]) - 0.0001);
+  y2 = ceil(fabs(src->xsize * rotate[3] - src->ysize * rotate[4]) - 0.0001);
+  ROT_DEBUG(fprintf(stderr, "x1 y1 " i_DFp " x2 y2 " i_DFp "\n", i_DFcp(x1, y1), i_DFcp(x2, y2)));
   newxsize = x1 > x2 ? x1 : x2;
   newysize = y1 > y2 ? y1 : y2;
   /* translate the centre back to the center of the image */
   xlate2[0] = 1;
-  xlate2[2] = -newxsize/2.0;
+  xlate2[2] = -(newxsize-1)/2.0;
   xlate2[4] = 1;
-  xlate2[5] = -newysize/2.0;
+  xlate2[5] = -(newysize-1)/2.0;
   xlate2[8] = 1;
+
+  ROT_DEBUG(dump_mat("xlate2", xlate2));
+
   i_matrix_mult(temp, xlate1, rotate);
   i_matrix_mult(matrix, temp, xlate2);
 
+  ROT_DEBUG(dump_mat("matrxi", matrix));
+
   return i_matrix_transform_bg(src, newxsize, newysize, matrix, backp, fbackp);
 }