1 %IM2GIF Convert a multiframe image to an animated GIF file
5 % im2gif infile outfile
7 % im2gif(...,
'-nocrop')
8 % im2gif(...,
'-nodither')
9 % im2gif(...,
'-ncolors', n)
10 % im2gif(...,
'-loops', n)
11 % im2gif(...,
'-delay', n)
13 % This
function converts a multiframe image to an animated GIF.
15 % To create an animation from a series of figures, export to a multiframe
16 % TIFF file
using export_fig, then convert to a GIF, as follows:
20 % export_fig test.tif -nocrop -append
22 % im2gif(
'test.tif',
'-delay', 0.5);
25 % infile -
string containing the name of the input image.
26 % outfile -
string containing the name of the output image (must have the
27 % .gif extension). Default: infile, with .gif extension.
28 % A - HxWxCxN array of input images, stacked along fourth dimension, to
29 % be converted to gif.
30 % -nocrop - option indicating that the borders of the output are not to
32 % -nodither - option indicating that dithering is not to be used when
33 % converting the image.
34 % -ncolors - option pair, the value of which indicates the maximum number
35 % of colors the GIF can have. This can also be a quantization
36 % tolerance, between 0 and 1. Default/maximum: 256.
37 % -loops - option pair, the value of which gives the number of times the
38 % animation is to be looped. Default: 65535.
39 % -delay - option pair, the value of which gives the time, in seconds,
40 % between frames. Default: 1/15.
42 % Copyright (C) Oliver Woodford 2011
44 function im2gif(A, varargin)
46 % Parse the input arguments
47 [A, options] = parse_args(A, varargin{:});
54 % Convert to indexed image
55 [h, w, c, n] = size(A);
56 A = reshape(permute(A, [1 2 4 3]), h, w*n, c);
57 map = unique(reshape(A, h*w*n, c),
'rows');
59 dither_str = {
'dither',
'nodither'};
60 dither_str = dither_str{1+(options.dither==0)};
61 if options.ncolors <= 1
62 [B, map] = rgb2ind(A, options.ncolors, dither_str);
64 [B, map] = rgb2ind(A, 256, dither_str);
67 [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str);
71 map = double(map) / 255;
74 B = rgb2ind(im2double(A), map);
76 B = reshape(B, h, w, 1, n);
79 map(B(1)+1,:) = im2double(A(1,1,:));
82 imwrite(B, map, options.outfile,
'LoopCount', round(options.loops(1)),
'DelayTime', options.delay);
85 %% Parse the input arguments
86 function [A, options] = parse_args(A, varargin)
88 options =
struct(
'outfile',
'', ...
95 % Go through the arguments
100 if ischar(varargin{a}) && ~isempty(varargin{a})
101 if varargin{a}(1) ==
'-' 102 opt = lower(varargin{a}(2:end));
105 options.crop =
false;
107 options.dither =
false;
109 if ~isfield(options, opt)
110 error('Option %s not recognized', varargin{a});
113 if ischar(varargin{a}) && ~ischar(options.(opt))
114 options.(opt) = str2double(varargin{a});
116 options.(opt) = varargin{a};
120 options.outfile = varargin{a};
125 if isempty(options.outfile)
127 error('No output filename given.');
129 % Generate the output filename from the input filename
130 [path, outfile] = fileparts(A);
131 options.outfile = fullfile(path, [outfile '.gif']);
140 %% Read image to uint8 rgb array
141 function [A, alpha] = imread_rgb(name)
143 info = imfinfo(name);
144 % Special case formats
145 switch lower(info(1).Format)
147 [A, map] = imread(name, 'frames', 'all');
149 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
150 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
151 A = permute(A, [1 2 5 4 3]);
154 A = cell(numel(info), 1);
156 [A{a}, map] = imread(name,
'Index', a,
'Info', info);
158 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
159 A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
161 if size(A{a}, 3) == 4
162 % TIFF in CMYK colourspace - convert to RGB
169 A{a}(:,:,4) = A{a}(:,:,4) / 255;
170 A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
175 [A, map, alpha] = imread(name);
176 A = A(:,:,:,1); % Keep only first frame of multi-frame files
178 map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
179 A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
180 elseif size(A, 3) == 4
181 % Assume 4th channel is an alpha matte
189 function A = crop_borders(A)
190 [h, w, c, n] = size(A);
191 bcol = A(ceil(end/2),1,:,1);
195 if ~all(col(A(:,l,a,:)) == bcol(a))
204 bcol = A(ceil(end/2),w,:,1);
208 if ~all(col(A(:,r,a,:)) == bcol(a))
217 bcol = A(1,ceil(end/2),:,1);
221 if ~all(col(A(t,:,a,:)) == bcol(a))
230 bcol = A(h,ceil(end/2),:,1);
234 if ~all(col(A(b,:,a,:)) == bcol(a))