changeset 18542:30aa4e85f8d5 stable

Fix writing and reading of multipage images. * __magick_read__.cc (encode_uint_image): reset the coordinates for each Magick::Image object so that writing of multipage images (matrices with non-singleton 4th dimension) work properly. Stride over the extra channels at the end of each page, to fix writing of multipage RGB and CMYK images. (read_images): correct stride over each frame for RGB and CMYK images. * imwrite.m: add tests to write and read multipage grayscale and RGB images. Reduce size of test images to speed up comparison.
author Carnë Draug <carandraug@octave.org>
date Tue, 04 Mar 2014 16:52:00 +0000
parents 11de7f82afe2
children 0bfbfb05b158
files libinterp/dldfcn/__magick_read__.cc scripts/image/imwrite.m
diffstat 2 files changed, 73 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/dldfcn/__magick_read__.cc	Sat Mar 01 22:07:44 2014 -0800
+++ b/libinterp/dldfcn/__magick_read__.cc	Tue Mar 04 16:52:00 2014 +0000
@@ -416,6 +416,7 @@
         }
     }
 
+  const octave_idx_type colour_stride = nRows * nCols;
   switch (type)
     {
     case Magick::BilevelType:           // Monochrome bi-level image
@@ -480,6 +481,7 @@
         img = T (dim_vector (nRows, nCols, 3, nFrames));
         P *img_fvec = img.fortran_vec ();
 
+        const octave_idx_type frame_stride  = colour_stride * 3;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             const Magick::PixelPacket *pix
@@ -487,10 +489,9 @@
                                                        col_cache, row_cache);
 
             octave_idx_type idx = 0;
-            img_fvec += nRows * nCols * frame;
             P *rbuf   = img_fvec;
-            P *gbuf   = img_fvec + nRows * nCols;
-            P *bbuf   = img_fvec + nRows * nCols * 2;
+            P *gbuf   = img_fvec + colour_stride;
+            P *bbuf   = img_fvec + colour_stride * 2;
 
             for (octave_idx_type col = 0; col < nCols; col++)
               {
@@ -504,6 +505,7 @@
                   }
                 pix -= col_shift;
               }
+            img_fvec += frame_stride;
           }
         break;
       }
@@ -516,6 +518,8 @@
         P *img_fvec = img.fortran_vec ();
         P *a_fvec   = alpha.fortran_vec ();
 
+        const octave_idx_type frame_stride  = colour_stride * 3;
+
         // Unlike the index for the other channels, this one won't need
         // to be reset on each frame since it's a separate matrix.
         octave_idx_type a_idx = 0;
@@ -526,10 +530,9 @@
                                                        col_cache, row_cache);
 
             octave_idx_type idx = 0;
-            img_fvec += nRows * nCols * frame;
             P *rbuf   = img_fvec;
-            P *gbuf   = img_fvec + nRows * nCols;
-            P *bbuf   = img_fvec + nRows * nCols * 2;
+            P *gbuf   = img_fvec + colour_stride;
+            P *bbuf   = img_fvec + colour_stride * 2;
 
             for (octave_idx_type col = 0; col < nCols; col++)
               {
@@ -544,6 +547,7 @@
                   }
                 pix -= col_shift;
               }
+            img_fvec += frame_stride;
           }
         retval(2) = alpha;
         break;
@@ -554,6 +558,7 @@
         img   = T (dim_vector (nRows, nCols, 4, nFrames));
         P *img_fvec = img.fortran_vec ();
 
+        const octave_idx_type frame_stride  = colour_stride * 4;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             const Magick::PixelPacket *pix
@@ -561,11 +566,10 @@
                                                        col_cache, row_cache);
 
             octave_idx_type idx = 0;
-            img_fvec += nRows * nCols * frame;
             P *cbuf   = img_fvec;
-            P *mbuf   = img_fvec + nRows * nCols;
-            P *ybuf   = img_fvec + nRows * nCols * 2;
-            P *kbuf   = img_fvec + nRows * nCols * 3;
+            P *mbuf   = img_fvec + colour_stride;
+            P *ybuf   = img_fvec + colour_stride * 2;
+            P *kbuf   = img_fvec + colour_stride * 3;
 
             for (octave_idx_type col = 0; col < nCols; col++)
               {
@@ -580,6 +584,7 @@
                   }
                 pix -= col_shift;
               }
+            img_fvec += frame_stride;
           }
         break;
       }
@@ -592,6 +597,8 @@
         P *img_fvec = img.fortran_vec ();
         P *a_fvec   = alpha.fortran_vec ();
 
+        const octave_idx_type frame_stride  = colour_stride * 4;
+
         // Unlike the index for the other channels, this one won't need
         // to be reset on each frame since it's a separate matrix.
         octave_idx_type a_idx = 0;
@@ -606,11 +613,10 @@
               = imvec[frameidx(frame)].getConstIndexes ();
 
             octave_idx_type idx = 0;
-            img_fvec += nRows * nCols * frame;
             P *cbuf   = img_fvec;
-            P *mbuf   = img_fvec + nRows * nCols;
-            P *ybuf   = img_fvec + nRows * nCols * 2;
-            P *kbuf   = img_fvec + nRows * nCols * 3;
+            P *mbuf   = img_fvec + colour_stride;
+            P *ybuf   = img_fvec + colour_stride * 2;
+            P *kbuf   = img_fvec + colour_stride * 3;
 
             for (octave_idx_type col = 0; col < nCols; col++)
               {
@@ -626,6 +632,7 @@
                   }
                 pix -= col_shift;
               }
+            img_fvec += frame_stride;
           }
         retval(2) = alpha;
         break;
@@ -1062,7 +1069,6 @@
     {
     case Magick::GrayscaleType:
       {
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1070,6 +1076,7 @@
                                                       Magick::DirectClass);
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1091,7 +1098,6 @@
 
     case Magick::GrayscaleMatteType:
       {
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1099,6 +1105,7 @@
                                                       Magick::DirectClass);
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1125,7 +1132,6 @@
         // The fortran_vec offset for the green and blue channels
         const octave_idx_type G_offset = nCols * nRows;
         const octave_idx_type B_offset = nCols * nRows * 2;
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1133,6 +1139,7 @@
                                                       Magick::DirectClass);
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1149,6 +1156,7 @@
             // Save changes to underlying image.
             m_img.syncPixels ();
             imvec.push_back (m_img);
+            img_fvec += B_offset;
           }
         break;
       }
@@ -1158,7 +1166,6 @@
         // The fortran_vec offset for the green and blue channels
         const octave_idx_type G_offset = nCols * nRows;
         const octave_idx_type B_offset = nCols * nRows * 2;
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1166,6 +1173,7 @@
                                                       Magick::DirectClass);
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1184,6 +1192,7 @@
             // Save changes to underlying image.
             m_img.syncPixels ();
             imvec.push_back (m_img);
+            img_fvec += B_offset;
           }
         break;
       }
@@ -1194,7 +1203,6 @@
         const octave_idx_type M_offset = nCols * nRows;
         const octave_idx_type Y_offset = nCols * nRows * 2;
         const octave_idx_type K_offset = nCols * nRows * 3;
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1202,6 +1210,7 @@
                                                       Magick::DirectClass);
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1219,6 +1228,7 @@
             // Save changes to underlying image.
             m_img.syncPixels ();
             imvec.push_back (m_img);
+            img_fvec += K_offset;
           }
         break;
       }
@@ -1229,7 +1239,6 @@
         const octave_idx_type M_offset = nCols * nRows;
         const octave_idx_type Y_offset = nCols * nRows * 2;
         const octave_idx_type K_offset = nCols * nRows * 3;
-        octave_idx_type GM_idx = 0;
         for (octave_idx_type frame = 0; frame < nFrames; frame++)
           {
             Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth,
@@ -1238,6 +1247,7 @@
 
             Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows);
             Magick::IndexPacket *ind = m_img.getIndexes ();
+            octave_idx_type GM_idx = 0;
             for (octave_idx_type col = 0; col < nCols; col++)
               {
                 for (octave_idx_type row = 0; row < nRows; row++)
@@ -1257,6 +1267,7 @@
             // Save changes to underlying image.
             m_img.syncPixels ();
             imvec.push_back (m_img);
+            img_fvec += K_offset;
           }
         break;
       }
--- a/scripts/image/imwrite.m	Sat Mar 01 22:07:44 2014 -0800
+++ b/scripts/image/imwrite.m	Tue Mar 04 16:52:00 2014 +0000
@@ -114,7 +114,6 @@
 
 endfunction
 
-
 %% Test input validation
 %!error imwrite ()                            # Wrong # of args
 %!error imwrite (1)                           # Wrong # of args
@@ -126,14 +125,52 @@
 %!error imwrite ([], "filename.jpg")          # Empty img matrix
 %!error imwrite (spones (2), "filename.jpg")  # Invalid sparse img
 
+## test typical usage with normal grayscale and RGB uint8 images
 %!testif HAVE_MAGICK
-%! imw = randi (255, 100, "uint8");
+%! bw  = randi (255, 10, "uint8");
+%! rgb = randi (255, 10, 10, 3, "uint8");
 %! filename = [tmpnam() ".png"];
 %! unwind_protect
-%!   imwrite (imw, filename);
-%!   imr = imread (filename);
+%!   imwrite (bw, filename);
+%!   bwr = imread (filename);
+%!   assert (bw, bwr)
+%!
+%!   imwrite (rgb, filename);
+%!   rgbr = imread (filename);
+%!   assert (rgb, rgbr)
 %! unwind_protect_cleanup
 %!   unlink (filename);
 %! end_unwind_protect
-%! assert (imw, imr)
 
+## Test writing of N dimensional images
+%!testif HAVE_MAGICK
+%! bw    = randi (255, 10, 10, 1, 5, "uint8");
+%! rgb   = randi (255, 3, 3, 3, 3, "uint8");
+%! filename = [tmpnam() ".tif"];
+%! unwind_protect
+%!   imwrite (bw, filename);
+%!   bwr = imread (filename, "Index", "all");
+%!   assert (bw, bwr)
+%!
+%!   imwrite (rgb, filename);
+%!   rgbr = imread (filename, "Index", "all");
+%!   assert (rgb, rgbr)
+%!
+%! unwind_protect_cleanup
+%!   unlink (filename);
+%! end_unwind_protect
+
+## test reading and writing of the alpha channel
+%!testif HAVE_MAGICK
+%! imw    = randi (255, 10, "uint8");
+%! alphaw = randi (255, 10, "uint8");
+%! filename = [tmpnam() ".png"];
+%! unwind_protect
+%!   imwrite (imw, filename, "Alpha", alphaw);
+%!   [imr, ~, alphar] = imread (filename);
+%!   assert (imw, imr)
+%!   assert (alphaw, alphar)
+%! unwind_protect_cleanup
+%!   unlink (filename);
+%! end_unwind_protect
+