File: imwrite.m

package info (click to toggle)
octave 9.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 144,300 kB
  • sloc: cpp: 332,784; ansic: 77,239; fortran: 20,963; objc: 9,396; sh: 8,213; yacc: 4,925; lex: 4,389; perl: 1,544; java: 1,366; awk: 1,259; makefile: 648; xml: 189
file content (246 lines) | stat: -rw-r--r-- 9,569 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
########################################################################
##
## Copyright (C) 2008-2024 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## This file is part of Octave.
##
## Octave 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.
##
## Octave 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 Octave; see the file COPYING.  If not, see
## <https://www.gnu.org/licenses/>.
##
########################################################################

## -*- texinfo -*-
## @deftypefn  {} {} imwrite (@var{img}, @var{filename})
## @deftypefnx {} {} imwrite (@var{img}, @var{filename}, @var{ext})
## @deftypefnx {} {} imwrite (@var{img}, @var{map}, @var{filename})
## @deftypefnx {} {} imwrite (@dots{}, @var{param1}, @var{val1}, @dots{})
## Write images in various file formats.
##
## The image @var{img} can be a binary, grayscale, RGB, or multi-dimensional
## image.  The size and class of @var{img} should be the same as what should
## be expected when reading it with @code{imread}: the 3rd and 4th dimensions
## reserved for color space, and multiple pages respectively.  If it's an
## indexed image, the colormap @var{map} must also be specified.
##
## If @var{ext} is not supplied, the file extension of @var{filename} is used
## to determine the format.  The actual supported formats are dependent on
## options made during the build of Octave.  Use @code{imformats} to check
## the support of the different image formats.
##
## Depending on the file format, it is possible to configure the writing of
## images with @var{param}, @var{val} pairs.  The following options are
## supported:
##
## @table @samp
## @item Alpha
## Alpha (transparency) channel for the image.  This must be a matrix with
## same class, and number of rows and columns of @var{img}.  In case of a
## multipage image, the size of the 4th dimension must also match and the third
## dimension must be a singleton.  By default, image will be completely opaque.
##
## @item Compression
## Compression to use one the image.  Can be one of the following: "none"
## (default), "bzip", "fax3", "fax4", "jpeg", "lzw", "rle", or "deflate".
## Note that not all compression types are available for all image formats
## in which it defaults to your @nospell{Magick} library.
##
## @item DelayTime
## For formats that accept animations (such as GIF), controls for how long a
## frame is displayed until it moves to the next one.  The value must be scalar
## (which will applied to all frames in @var{img}), or a vector of length
## equal to the number of frames in @var{im}.  The value is in seconds, must
## be between 0 and 655.35, and defaults to 0.5.
##
## @item DisposalMethod
## For formats that accept animations (such as GIF), controls what happens to
## a frame before drawing the next one.  Its value can be one of the
## following strings: "doNotSpecify" (default); "leaveInPlace"; "restoreBG";
## and "restorePrevious", or a cell array of those string with length equal
## to the number of frames in @var{img}.
##
## @item LoopCount
## For formats that accept animations (such as GIF), controls how many times
## the sequence is repeated.  A value of Inf means an infinite loop (default),
## a value of 0 or 1 that the sequence is played only once (loops zero times),
## while a value of 2 or above loops that number of times (looping twice means
## it plays the complete sequence 3 times).  This option is ignored when there
## is only a single image at the end of writing the file.
##
## @item Quality
## Set the quality of the compression.  The value should be an integer
## between 0 and 100, with larger values indicating higher visual quality and
## lower compression.  Defaults to 75.
##
## @item WriteMode
## Some file formats, such as TIFF and GIF, are able to store multiple images
## in a single file.  This option specifies if @var{img} should be appended
## to the file (if it exists) or if a new file should be created for it
## (possibly overwriting an existing file).  The value should be the string
## @qcode{"Overwrite"} (default), or @qcode{"Append"}.
##
## Despite this option, the most efficient method of writing a multipage
## image is to pass a 4 dimensional @var{img} to @code{imwrite}, the same
## matrix that could be expected when using @code{imread} with the option
## @qcode{"Index"} set to @qcode{"all"}.
##
## @end table
##
## @seealso{imread, imfinfo, imformats}
## @end deftypefn

function imwrite (varargin)

  if (nargin < 2)
    print_usage ();
  endif

  [filename, ext] = imwrite_filename (varargin{2:end});

  fmt = imformats (ext);
  ## When there is no match, fmt will be a 1x1 structure with
  ## no fields, so we can't just use 'isempty (fmt)'.
  if (numfields (fmt) == 0)
    if (isempty (ext))
      error ("imwrite: no extension found for %s to identify the image format",
             filename);
    endif
    warning ("imwrite: unlisted image format %s (see imformats).  Trying to save anyway.",
             ext);
    __imwrite__ (varargin{:});
  else
    fmt.write (varargin{:});
  endif

endfunction


## Test input validation
%!error <Invalid call> imwrite ()             # Wrong # of args
%!error <Invalid call> imwrite (1)            # Wrong # of args
%!error imwrite ({"cell"}, "filename.jpg")    # Wrong class for img
%!error imwrite (1, [], "filename.jpg")       # Empty image map
%!error imwrite (1, 2, 3)                     # No filename specified
%!error imwrite (1, "filename")               # No fmt specified
%!error imwrite (1, "filename", "junk")       # Invalid fmt specified
%!error imwrite ([], "filename.jpg")          # Empty img matrix
%!error imwrite (spones (2), "filename.jpg")  # Invalid sparse img

%!function [r, cmap, a] = write_and_read (format, varargin)
%!  filename = [tempname() format];
%!  unwind_protect
%!    imwrite (varargin{1}, filename, varargin{2:end});
%!    [r, cmap, a] = imread (filename, "Index", "all");
%!  unwind_protect_cleanup
%!    unlink (filename);
%!  end_unwind_protect
%!endfunction

## typical usage with grayscale uint8 images
%!testif HAVE_MAGICK
%! gray = randi (255, 10, 10, 1, "uint8");
%! r = write_and_read (".tif", gray);
%! assert (r, gray);

## grayscale uint8 images with alpha channel
%!testif HAVE_MAGICK
%! gray  = randi (255, 10, 10, 1, "uint8");
%! alpha = randi (255, 10, 10, 1, "uint8");
%! [r, ~, a] = write_and_read (".tif", gray, "Alpha", alpha);
%! assert (r, gray);
%! assert (a, alpha);

## multipage grayscale uint8 images
%!testif HAVE_MAGICK
%! gray = randi (255, 10, 10, 1, 5, "uint8");
%! r    = write_and_read (".tif", gray);
%! assert (r, gray);

## multipage RGB uint8 images with alpha channel
%!testif HAVE_MAGICK
%! gray  = randi (255, 10, 10, 3, 5, "uint8");
%! alpha = randi (255, 10, 10, 1, 5, "uint8");
%! [r, ~, a] = write_and_read (".tif", gray, "Alpha", alpha);
%! assert (r, gray);
%! assert (a, alpha);

## typical usage with RGB uint8 images
%!testif HAVE_MAGICK
%! rgb = randi (255, 10, 10, 3, "uint8");
%! r = write_and_read (".tif", rgb);
%! assert (r, rgb);

## RGB uint8 images with alpha channel
%!testif HAVE_MAGICK
%! rgb   = randi (255, 10, 10, 3, "uint8");
%! alpha = randi (255, 10, 10, 1, "uint8");
%! [r, ~, a] = write_and_read (".tif", rgb, "Alpha", alpha);
%! assert (r, rgb);
%! assert (a, alpha);

## multipage RGB uint8 images
%!testif HAVE_MAGICK
%! rgb = randi (255, 10, 10, 3, 5, "uint8");
%! r = write_and_read (".tif", rgb);
%! assert (r, rgb);

## multipage RGB uint8 images with alpha channel
%!testif HAVE_MAGICK
%! rgb   = randi (255, 10, 10, 3, 5, "uint8");
%! alpha = randi (255, 10, 10, 1, 5, "uint8");
%! [r, ~, a] = write_and_read (".tif", rgb, "Alpha", alpha);
%! assert (r, rgb);
%! assert (a, alpha);

%!testif HAVE_MAGICK
%! gray = repmat (uint8 (0:255), 100, 1);
%! [g] = write_and_read (".jpeg", gray);
%! assert (g, gray, 2);

%!testif HAVE_MAGICK
%! gray = repmat (uint8 (0:255), 100, 1);
%! [g] = write_and_read (".jpeg", gray, "quality", 100);
%! assert (g, gray);

%!function compression = get_bmp_compression (ext, cmap = [], varargin)
%!  gray = repmat (uint8 (0:255), 100, 1);
%!  filename = [tempname() ext];
%!  unwind_protect
%!    if (isempty (cmap))
%!      imwrite (gray, filename, varargin{1:end});
%!    else
%!      imwrite (gray, cmap, filename, varargin{1:end});
%!    endif
%!    fid = fopen (filename);
%!    unwind_protect
%!      compression = fread (fid, 31)(end);
%!    unwind_protect_cleanup
%!      fclose (fid);
%!    end_unwind_protect
%!  unwind_protect_cleanup
%!    unlink (filename);
%!  end_unwind_protect
%!endfunction

## BMP images must be saved uncompressed by default
%!testif HAVE_MAGICK <*45565>
%! assert (get_bmp_compression ("", [], "BMP"), 0);
%! assert (get_bmp_compression ("", [], "bmp"), 0);
%! assert (get_bmp_compression (".BMP"), 0);
%! assert (get_bmp_compression (".bmp"), 0);
%! assert (get_bmp_compression (".bmp", [], "bmp"), 0);
%! assert (get_bmp_compression ("", gray (256), "bmp"), 0);
%! assert (get_bmp_compression (".bmp", gray (256), "Compression", "rle"), 1);