Mercurial > hg > octave-nkf
changeset 18610: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 +++ b/libinterp/dldfcn/__magick_read__.cc @@ -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 +++ b/scripts/image/imwrite.m @@ -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 +