diff -r de7d55650ad7 inst/imtransform.m
--- a/inst/imtransform.m	Wed Jul 28 09:47:07 2021 +0200
+++ b/inst/imtransform.m	Mon Aug 30 08:09:23 2021 +0300
@@ -32,21 +32,31 @@
 ## @table @asis
 ## @item "udata"
 ## Specifies the input space horizontal limits. @var{val} must be a two
-## elements vector [minval maxval]. Default: [1 columns(@var{IM_IN})]
+## elements vector [minval maxval] in ascending order.
+## Default: [1 columns(@var{IM_IN})]
 ##
 ## @item "vdata"
 ## Specifies the input space vertical limits. @var{val} must be a two
-## elements vector [minval maxval]. Default: [1 rows(@var{IM_IN})]
+## elements vector [minval maxval] in ascending order.
+## Default: [1 rows(@var{IM_IN})]
 ##
 ## @item "xdata"
 ## Specifies the required output space horizontal limits. @var{val} must
-## be a two elements vector [minval maxval]. Default: estimated using
-## udata, vdata and findbounds function.
+## be a two elements vector [first_col last_col] represents the coordinates
+## of the first column and the last column of output image in the world
+## coordinate system.
+## Note: xdata can be in descending order, which cause a horizontal flip of
+## the output image.
+## Default: estimated using udata, vdata and findbounds function.
 ##
 ## @item "ydata"
 ## Specifies the required output space vertical limits. @var{val} must
-## be a two elements vector [minval maxval]. Default: estimated using
-## udata, vdata and findbounds function.
+## be a two elements vector [first_row last_row] represents the coordinates
+## of the first row and the last row of output image in the world
+## coordinate system.
+## Note: ydata can be in descending order, which cause a vetictal flip of
+## the output image.
+## Default: estimated using udata, vdata and findbounds function.
 ##
 ## @item "xyscale"
 ## Specifies the size of pixels in the output space. If a scalar
@@ -95,6 +105,8 @@
   xyscale = [];
   imsize = [];
   fillvalues = zeros (1, imdepth);
+  xdir = 1;
+  ydir = 1;
 
   if (isempty (varargin))
     xydata = findbounds (T, [udata vdata]);
@@ -147,6 +159,12 @@
         endif
       endif
     endfor
+    
+    # checking that udata and vdata are in ascending order
+    if (udata(1) > udata(2) || vdata(1) > vdata(2))
+      error ("imtransform: udata and vdata should be in ascending order")
+    endif
+    
     if (isempty (xdata) && isempty (ydata))
       xydata = findbounds (T, [udata vdata]);
       xdata = xydata(:,1);
@@ -159,6 +177,15 @@
       ydata = xydata(:,2);
     endif
 
+    # handle descending order of xdata, ydata(bug #59953)
+    if (diff (xdata) < 0)
+      xdata = [xdata(2); xdata(1)];
+      xdir = -1;
+    endif
+    if (diff (ydata) < 0)
+      ydata = [ydata(2); ydata(1)];
+      ydir = -1;
+    endif
     ## size and xyscale
     tst = strcmp ("size", props);
     if (any (tst))
@@ -241,8 +268,21 @@
   for layer = 1:imdepth
     imout(:,:,layer) = interp2 (uu, vv, im(:,:,layer), ...
                                 uui, vvi, interp, fillvalues(layer));
+    if (xdir == -1)
+      imout(:,:,layer) = fliplr (imout(:,:,layer));
+    endif
+    if (ydir == -1)
+      imout(:,:,layer) = flipud (imout(:,:,layer));
+    endif
   endfor
   if (nargout != 0)
+    # revert xdata and ydata to original values
+    if (xdir == -1)
+      xdata = [xdata(2); xdata(1)];
+    endif
+    if (ydir == -1)
+      ydata = [ydata(2); ydata(1)];
+    endif
     varargout = {imout, xdata(:).', ydata(:).'};
   endif
 endfunction
@@ -420,3 +460,29 @@
 %! T = maketform ('affine', tmat);
 %! im2 = imtransform (im, T, "xyscale", [0.5 0.5]);
 %! assert (size (im2), [3 3])
+
+## Test descending order of xdata/ydata (bug #59953)
+%!test
+%! im = [1,2,3,4; 5,6,7,8;9,10,11,12;13,14,15,16];
+%! tmat = [eye(2); 0 0];
+%! T = maketform ('affine', tmat);
+%! im2 = imtransform (im, T, 'xdata', [1 4], 'ydata', [4 1]);
+%! assert (im2, [13,14,15,16;9,10,11,12;5,6,7,8;1,2,3,4])
+%!
+%! im2 = imtransform (im, T, 'xdata', [4 1], 'ydata', [1 4]);
+%! assert (im2, [4,3,2,1;8,7,6,5;12,11,10,9;16,15,14,13])
+%!
+%! [im2, xd, yd] = imtransform (im, T, 'xdata', [4 1], 'ydata', [4 1]);
+%! assert (im2, [16,15,14,13;12,11,10,9;8,7,6,5;4,3,2,1])
+%! assert (xd, [4,1])
+%! assert (yd, [4,1])
+%!
+%!error <Invalid call to imtransform> imtransform ()
+%!error <Invalid call to imtransform> imtransform (rand(2))
+%!error <imtransform: udata and vdata should be in ascending order> ...
+%!        imtransform (rand(2), maketform ('affine', [eye(2); 0 0]), ...
+%!        'udata', [1 2], 'vdata', [2 1]);
+%!error <imtransform: udata and vdata should be in ascending order> ...
+%!        imtransform (rand(2), maketform ('affine', [eye(2); 0 0]), ...
+%!        'udata', [2 1], 'vdata', [1 2]);
+
