changeset 20441:5b8e4f668c53

Add compression option to imwrite and default to "none" (bug #45565) * libinterp/dldfcn/__magick_read__.cc: we did not specify compression type and let it up to GM coder. However, Matlab users seem to be expect it to be uncompressed since Matlab only does that (except for jpeg). So we add the compression method and apply to the images being writen. * scripts/image/imwrite.m: document new option and add tests (bug was about bmp and type compression is defined at offset byte 30) * scripts/image/private/__imwrite__.m: parse new compression option.
author Carnë Draug <carandraug@octave.org>
date Tue, 28 Jul 2015 17:43:23 +0100
parents e3f84a8c6788
children 4bde15a9c8bb
files libinterp/dldfcn/__magick_read__.cc scripts/image/imwrite.m scripts/image/private/__imwrite__.m
diffstat 3 files changed, 67 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/dldfcn/__magick_read__.cc	Tue Jul 28 08:52:39 2015 -0700
+++ b/libinterp/dldfcn/__magick_read__.cc	Tue Jul 28 17:43:23 2015 +0100
@@ -1551,6 +1551,23 @@
   // Note that this only needs to be set on the first frame
   imvec[0].animationIterations (options.getfield ("loopcount").uint_value ());
 
+  const std::string compression = options.getfield ("compression").string_value ();
+#define COMPRESS_MAGICK_IMAGE_VECTOR(COMPRESSION_STRING, GM_TYPE) \
+  if (compression == COMPRESSION_STRING) \
+    for (std::vector<Magick::Image>::size_type i = 0; i < imvec.size (); i++) \
+      imvec[i].compressType (GM_TYPE);
+
+  COMPRESS_MAGICK_IMAGE_VECTOR("none", Magick::NoCompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("bzip", Magick::BZipCompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("fax3", Magick::FaxCompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("fax4", Magick::Group4Compression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("jpeg", Magick::JPEGCompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("lzw", Magick::LZWCompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("rle", Magick::RLECompression)
+  else COMPRESS_MAGICK_IMAGE_VECTOR("deflate", Magick::ZipCompression)
+
+#undef COMPRESS_MAGICK_IMAGE_VECTOR
+
   write_file (filename, ext, imvec);
   if (error_state)
     return retval;
--- a/scripts/image/imwrite.m	Tue Jul 28 08:52:39 2015 -0700
+++ b/scripts/image/imwrite.m	Tue Jul 28 17:43:23 2015 +0100
@@ -46,6 +46,12 @@
 ## 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 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
@@ -200,3 +206,32 @@
 %! [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 (bug #45565)
+%!testif HAVE_MAGICK
+%! 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)
--- a/scripts/image/private/__imwrite__.m	Tue Jul 28 08:52:39 2015 -0700
+++ b/scripts/image/private/__imwrite__.m	Tue Jul 28 17:43:23 2015 +0100
@@ -46,7 +46,8 @@
                     "quality",   75,
                     "delaytime", ones (1, size (img, 4)) *500, # 0.5 seconds
                     "loopcount", 0, ## this is actually Inf
-                    "alpha",     cast ([], class (img)));
+                    "alpha",     cast ([], class (img)),
+                    "compression", "none");
 
   for idx = 1:2:numel (param_list)
 
@@ -67,6 +68,19 @@
                  param_list{idx});
         endif
 
+      case "compression"
+        options.compression = param_list{idx+1};
+        if (! ischar (options.compression))
+          error ("imwrite: value for %s option must be a string",
+                 param_list{idx});
+        endif
+        options.compression = tolower (options.compression);
+        if (! any (strcmp (options.compression, {"none", "bzip", "fax3", ...
+                                                 "fax4", "jpeg", "lzw", ...
+                                                 "rle", "deflate"})))
+          error ("imwrite: invalid compression `%s'", options.compression);
+        endif
+
       case "delaytime"
         options.delaytime = param_list{idx+1};
         if (! isnumeric (options.delaytime))