# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1495971722 -7200
#      Sun May 28 13:42:02 2017 +0200
# Node ID 968999e45d1c7f8fd842e36d9a3d8408d5d5eea8
# Parent  2aab625b502caf3c52d5e41a767223b605b11ee3
Add movie function

* scripts/image/movie.m: new function file
* getframe.m: add movie to seealso
* scripts/image/module.mk: update
* image.txi: add movie doc. Reorganise part of "Representing Images" section

diff -r 2aab625b502c -r 968999e45d1c NEWS
--- a/NEWS	Tue May 23 15:01:27 2017 +0200
+++ b/NEWS	Sun May 28 13:42:02 2017 +0200
@@ -36,6 +36,7 @@
       gsvd
       hgtransform
       getframe
+      movie
 
  ** Deprecated functions.
 
diff -r 2aab625b502c -r 968999e45d1c doc/interpreter/image.txi
--- a/doc/interpreter/image.txi	Tue May 23 15:01:27 2017 +0200
+++ b/doc/interpreter/image.txi	Sun May 28 13:42:02 2017 +0200
@@ -140,10 +140,11 @@
 an RGB color.  The color map must be of class @code{double} with values
 between 0 and 1.
 
+The following convenience functions are available for convertion between image 
+formats.
+
 @DOCSTRING(im2double)
 
-@DOCSTRING(iscolormap)
-
 @DOCSTRING(gray2ind)
 
 @DOCSTRING(ind2gray)
@@ -152,14 +153,27 @@
 
 @DOCSTRING(ind2rgb)
 
+Octave also provides tools to produce and work with movie frame structures. 
+Those structures encapsulate the image data (@qcode{"cdata"} field) together 
+with the corresponding colormap (@qcode{"colormap"} field).
+
 @DOCSTRING(getframe)
 
+@DOCSTRING(movie)
+
 @DOCSTRING(frame2im)
 
 @DOCSTRING(im2frame)
 
+The @code{colormap} function is used to change the colormap of the current axes or figure.
+
 @DOCSTRING(colormap)
 
+@DOCSTRING(iscolormap)
+
+The following functions return predefined colormaps, the same that can be 
+requested by name using the @code{colormap} function. 
+
 @DOCSTRING(rgbplot)
 
 @DOCSTRING(autumn)
diff -r 2aab625b502c -r 968999e45d1c scripts/image/getframe.m
--- a/scripts/image/getframe.m	Tue May 23 15:01:27 2017 +0200
+++ b/scripts/image/getframe.m	Sun May 28 13:42:02 2017 +0200
@@ -39,7 +39,7 @@
 ## @var{hax} to be catured. Whatever the figure @qcode{"units"} property,
 ## @var{rect} must be defined in @strong{pixels}.
 ## 
-## @seealso{im2frame, frame2im}
+## @seealso{im2frame, frame2im, movie}
 ## @end deftypefn
 
 function im = getframe (h = [], rect = [])
diff -r 2aab625b502c -r 968999e45d1c scripts/image/module.mk
--- a/scripts/image/module.mk	Tue May 23 15:01:27 2017 +0200
+++ b/scripts/image/module.mk	Sun May 28 13:42:02 2017 +0200
@@ -46,6 +46,7 @@
   %reldir%/iscolormap.m \
   %reldir%/jet.m \
   %reldir%/lines.m \
+  %reldir%/movie.m \
   %reldir%/ntsc2rgb.m \
   %reldir%/ocean.m \
   %reldir%/pink.m \
diff -r 2aab625b502c -r 968999e45d1c scripts/image/movie.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/image/movie.m	Sun May 28 13:42:02 2017 +0200
@@ -0,0 +1,204 @@
+## Copyright (C) 2017 Pantxo Diribarne
+## 
+## This program is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {} {} movie (@var{mov})
+## @deftypefnx {} {} movie (@var{mov}, @var{n})
+## @deftypefnx {} {} movie (@var{mov}, @var{n}, @var{fps})
+## @deftypefnx {} {} movie (@var{h}, @dots{})
+## Play a movie defined by an array of frame structures
+##
+## The movie @var{mov} must be a struct array of frames with fields
+## @qcode{"cdata"} and @qcode{"colormap"}, as returned by the
+## @code{getframe} function. By default all images are diplayed
+## once, at 12 fps, in the current axes.
+##
+## The optional argument @var{n} is a scalar or vector of integers that
+## control the number of times the movie is displayed and the particular
+## frames that are shown:
+## @table @asis
+## @item First element:
+## @table @asis
+## @item @var{n}(1) > 0
+## Play the movie @var{n}(1) times
+## @item @var{n}(1) < 0
+## Play the movie -@var{n}(1) times alternatively in forward and backward order
+## @end table
+## @item Other elements (if any):
+## Indexes of the frames in @var{mov} that will be displayed
+## @end table
+##
+## If the first argument is a handle to a figure or axes @var{h}, the movie is
+## played in that figure or axes instead of the current axes.
+##
+## @seealso{getframe, im2frame, frame2im}
+## @end deftypefn
+
+function movie (varargin)
+  nargs = numel (varargin);
+  if (nargs == 0 )
+    print_usage ();
+  endif
+
+  ## Extract first handle argument
+  hax = [];
+  if (isaxes (varargin{1}))
+    hax = varargin{1};
+    varargin(1) = [];
+  elseif (isfigure (varargin{1}))
+    hax = get (varargin{1}, "currentaxes");
+    if (isempty (hax))
+      hax = axes ("parent", varargin{1});
+    endif
+    varargin(1) = [];
+  endif
+
+  ## Extract other arguments
+  n = 1;
+  fps = 12;
+  idx = [];
+  nargs = numel (varargin);
+  if (nargs == 0)
+    print_usage ();
+  elseif (nargs >= 1)
+    mov = varargin{1};
+    if (! isfield (mov, "cdata") || ! isfield (mov, "colormap"))
+      error ("movie: expect MOV to be a frame struct array")
+    endif
+
+    if (nargs >= 2)
+      n = varargin{2};
+      if (! isnumeric (n) || any (fix(n) != n) || any (n == 0))
+        error ("movie: expect N to be non zero integer")
+      elseif (! isscalar (n))
+        idx = n(2:end)(:)';
+        n = n(1);
+        if (any (idx < 1) || any (idx > numel (mov)))
+          error (["movie: expect all elements N(2:end) to be indexes ", ...
+                  "in the MOV struct array"]);
+
+        endif
+      endif
+        
+      if (nargs >= 3)
+        fps = varargin{3};
+        if (! isnumeric (fps))
+          error ("movie: expect FPS to be numeric")
+        endif
+      endif
+    endif
+  endif
+
+  if (isempty (hax))
+    hax = gca ();
+  endif
+
+  ## Build the list of frames to be displayed
+  if (isempty (idx))
+    idx = (1:numel (mov));
+  endif
+
+  if (n > 0)
+    idx = repmat (idx, 1, n);
+  else
+    n = - n;
+    tmp = repmat ([idx fliplr(idx)], 1, fix (n/2));
+    if (fix (n/2) != n/2)
+      idx = [tmp idx];
+    else
+      idx = tmp;
+    endif
+  endif
+
+  tau = 1/fps;
+  him = image ("parent", hax, "cdata", mov(1).cdata);
+  tic ();
+  set (hax, "ydir", "reverse", "visible", "off");
+  for ii = idx
+    pause (tau - toc ());
+    if (! isempty (mov(ii).colormap))
+      set (hax, "colormap", mov(ii).colormap)
+    endif
+    set (him, "cdata", mov(ii).cdata);
+    tic ();
+  endfor
+  
+endfunction
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, 'uint8');
+%! mov(nframes) = struct ('cdata', [], 'colormap', []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play movie forward 2 times"
+%! movie (mov, 2);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, 'uint8');
+%! mov(nframes) = struct ('cdata', [], 'colormap', []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play movie forward and backward 5 times at 25 fps"
+%! movie (mov, -5, 25);
+
+%!demo
+%! nframes = 20;
+%! colors = jet (nframes);
+%! baseim = ones (20, 20, 3, 'uint8');
+%! mov(nframes) = struct ('cdata', [], 'colormap', []);
+%! for ii = 1:nframes
+%!   im = baseim * 255;
+%!   im(:,ii,1) = colors(ii,1) * 255;
+%!   im(:,ii,2) = colors(ii,2) * 255;
+%!   im(:,ii,3) = colors(ii,3) * 255;
+%!   mov(ii).cdata = im;
+%! endfor
+%! clf ();
+%! title "Play downsampled movie 5 times" 
+%! movie (mov, [5 1:3:nframes]);
+
+%!demo
+%! clf ();
+%! z = sombrero ();
+%! hs = surf (z);
+%! axis manual
+%! nframes = 50;
+%! mov(nframes) = struct ('cdata', [], 'colormap', []);
+%! for ii = 1:nframes
+%!   set (hs, 'zdata', z * sin (2*pi*ii/nframes));
+%!   mov(ii) = getframe ();
+%! endfor
+%! clf ();
+%! movie (mov, 5, 25);
+
+%!error <expect MOV to be a frame struct array> movie (2)
+%!error <expect N to be non zero integer> movie (struct ("cdata", [], "colormap", []), 2.3)
+%!error <expect N to be non zero integer> movie (struct ("cdata", [], "colormap", []), [2.3 -6])
