]> git.imager.perl.org - imager.git/blobdiff - rotate.c
[rt #69008] depend on a CPAN::Meta that depends on JSON::PP
[imager.git] / rotate.c
index d4891c00e2bc775ff767691b941957948055dbca..90cf5912ba8f4f2a6004d0e3fa696a119827e432 100644 (file)
--- a/rotate.c
+++ b/rotate.c
@@ -17,11 +17,12 @@ Other rotations will be added as tuits become available.
 */
 
 #include "imager.h"
+#include "imageri.h"
 #include <math.h> /* for floor() */
 
 i_img *i_rotate90(i_img *src, int degrees) {
   i_img *targ;
-  int x, y;
+  i_img_dim x, y;
 
   i_clear_error();
 
@@ -79,8 +80,8 @@ i_img *i_rotate90(i_img *src, int degrees) {
     return targ;
   }
   else if (degrees == 270 || degrees == 90) {
-    int tx, txstart, txinc;
-    int ty, tystart, tyinc;
+    i_img_dim tx, txstart, txinc;
+    i_img_dim ty, tystart, tyinc;
 
     if (degrees == 270) {
       txstart = 0;
@@ -150,7 +151,6 @@ i_img *i_rotate90(i_img *src, int degrees) {
   }
 }
 
-/* hopefully this will be inlined  (it is with -O3 with gcc 2.95.4) */
 /* linear interpolation */
 static i_color interp_i_color(i_color before, i_color after, double pos,
                               int channels) {
@@ -158,8 +158,30 @@ static i_color interp_i_color(i_color before, i_color after, double pos,
   int ch;
 
   pos -= floor(pos);
-  for (ch = 0; ch < channels; ++ch)
-    out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+  if (channels == 1 || channels == 3) {
+    for (ch = 0; ch < channels; ++ch)
+      out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+  }
+  else {
+    int total_cover = (1-pos) * before.channel[channels-1]
+      + pos * after.channel[channels-1];
+
+    total_cover = I_LIMIT_8(total_cover);
+    if (total_cover) {
+      double before_alpha = before.channel[channels-1] / 255.0;
+      double after_alpha = after.channel[channels-1] / 255.0;
+      double total_alpha = before_alpha * (1-pos) + after_alpha * 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;
+
+       out.channel[ch] = I_LIMIT_8(out_level);
+      }
+    }
+
+    out.channel[channels-1] = total_cover;
+  }
 
   return out;
 }
@@ -172,18 +194,40 @@ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
   int ch;
 
   pos -= floor(pos);
-  for (ch = 0; ch < channels; ++ch)
-    out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+  if (channels == 1 || channels == 3) {
+    for (ch = 0; ch < channels; ++ch)
+      out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
+  }
+  else {
+    double total_cover = (1-pos) * before.channel[channels-1]
+      + pos * after.channel[channels-1];
+
+    total_cover = I_LIMIT_DOUBLE(total_cover);
+    if (total_cover) {
+      double before_alpha = before.channel[channels-1];
+      double after_alpha = after.channel[channels-1];
+      double total_alpha = before_alpha * (1-pos) + after_alpha * pos;
+
+      for (ch = 0; ch < channels-1; ++ch) {
+       double out_level = ((1-pos) * before.channel[ch] * before_alpha + 
+                        pos * after.channel[ch] * after_alpha) / total_alpha;
+
+       out.channel[ch] = I_LIMIT_DOUBLE(out_level);
+      }
+    }
+
+    out.channel[channels-1] = total_cover;
+  }
 
   return out;
 }
 
-i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *matrix,
+i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix,
                             const i_color *backp, const i_fcolor *fbackp) {
   i_img *result = i_sametype(src, xsize, ysize);
-  int x, y;
+  i_img_dim x, y;
   int ch;
-  int i, j;
+  i_img_dim i, j;
   double sx, sy, sz;
 
   if (src->type == i_direct_type) {
@@ -211,19 +255,22 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
           /* dividing by sz gives us the ability to do perspective 
              transforms */
           sz = x * matrix[6] + y * matrix[7] + matrix[8];
-          if (abs(sz) > 0.0000001) {
+          if (fabs(sz) > 0.0000001) {
             sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
             sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
           }
+         else {
+           sx = sy = 0;
+         }
 
           /* anything outside these ranges is either a broken co-ordinate
              or outside the source */
-          if (abs(sz) > 0.0000001 
+          if (fabs(sz) > 0.0000001 
               && sx >= -1 && sx < src->xsize
               && sy >= -1 && sy < src->ysize) {
 
-            if (sx != (int)sx) {
-              if (sy != (int)sy) {
+            if (sx != (i_img_dim)sx) {
+              if (sy != (i_img_dim)sy) {
                 i_color c[2][2]; 
                 i_color ci2[2];
                 for (i = 0; i < 2; ++i)
@@ -243,7 +290,7 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
               }
             }
             else {
-              if (sy != (int)sy) {
+              if (sy != (i_img_dim)sy) {
                 i_color ci2[2];
                 for (i = 0; i < 2; ++i)
                   if (i_gpix(src, sx, floor(sy)+i, ci2+i))
@@ -286,19 +333,22 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
           /* dividing by sz gives us the ability to do perspective 
              transforms */
           sz = x * matrix[6] + y * matrix[7] + matrix[8];
-          if (abs(sz) > 0.0000001) {
+          if (fabs(sz) > 0.0000001) {
             sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
             sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
           }
+          else {
+            sx = sy = 0;
+          }
 
           /* anything outside these ranges is either a broken co-ordinate
              or outside the source */
-          if (abs(sz) > 0.0000001 
+          if (fabs(sz) > 0.0000001 
               && sx >= -1 && sx < src->xsize
               && sy >= -1 && sy < src->ysize) {
 
-            if (sx != (int)sx) {
-              if (sy != (int)sy) {
+            if (sx != (i_img_dim)sx) {
+              if (sy != (i_img_dim)sy) {
                 i_fcolor c[2][2]; 
                 i_fcolor ci2[2];
                 for (i = 0; i < 2; ++i)
@@ -318,7 +368,7 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
               }
             }
             else {
-              if (sy != (int)sy) {
+              if (sy != (i_img_dim)sy) {
                 i_fcolor ci2[2];
                 for (i = 0; i < 2; ++i)
                   if (i_gpixf(src, sx, floor(sy)+i, ci2+i))
@@ -347,7 +397,7 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
     i_palidx back = 0;
     i_color min;
     int minval = 256 * 4;
-    int ix, iy;
+    i_img_dim ix, iy;
     i_color want_back;
     i_fsample_t fsamp;
 
@@ -390,6 +440,9 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
           sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
           sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
         }
+        else {
+          sx = sy = 0;
+        }
         
         /* anything outside these ranges is either a broken co-ordinate
            or outside the source */
@@ -398,8 +451,8 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
             && sy >= -0.5 && sy < src->ysize-0.5) {
           
           /* all the world's an integer */
-          ix = (int)(sx+0.5);
-          iy = (int)(sy+0.5);
+          ix = (i_img_dim)(sx+0.5);
+          iy = (i_img_dim)(sy+0.5);
           if (!i_gpal(src, ix, ix+1, iy, vals+x))
            vals[i] = back;
         }
@@ -415,7 +468,7 @@ i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, const double *mat
   return result;
 }
 
-i_img *i_matrix_transform(i_img *src, int xsize, int ysize, const double *matrix) {
+i_img *i_matrix_transform(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix) {
   return i_matrix_transform_bg(src, xsize, ysize, matrix, NULL, NULL);
 }
 
@@ -441,7 +494,7 @@ i_img *i_rotate_exact_bg(i_img *src, double amount,
   double rotate[9];
   double xlate2[9] = { 0 };
   double temp[9], matrix[9];
-  int x1, x2, y1, y2, newxsize, newysize;
+  i_img_dim x1, x2, y1, y2, newxsize, newysize;
 
   /* first translate the centre of the image to (0,0) */
   xlate1[0] = 1;
@@ -461,17 +514,17 @@ i_img *i_rotate_exact_bg(i_img *src, double amount,
   rotate[7] = 0;
   rotate[8] = 1;
 
-  x1 = ceil(abs(src->xsize * rotate[0] + src->ysize * rotate[1]));
-  x2 = ceil(abs(src->xsize * rotate[0] - src->ysize * rotate[1]));
-  y1 = ceil(abs(src->xsize * rotate[3] + src->ysize * rotate[4]));
-  y2 = ceil(abs(src->xsize * rotate[3] - src->ysize * rotate[4]));
+  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]));
   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;
+  xlate2[2] = -newxsize/2.0;
   xlate2[4] = 1;
-  xlate2[5] = -newysize/2;
+  xlate2[5] = -newysize/2.0;
   xlate2[8] = 1;
   i_matrix_mult(temp, xlate1, rotate);
   i_matrix_mult(matrix, temp, xlate2);