__magick_read__.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2002-2012 Andy Adler
00004 Copyright (C) 2008 Thomas L. Scofield
00005 Copyright (C) 2010 David Grundberg
00006 
00007 This file is part of Octave.
00008 
00009 Octave is free software; you can redistribute it and/or modify it
00010 under the terms of the GNU General Public License as published by the
00011 Free Software Foundation; either version 3 of the License, or (at your
00012 option) any later version.
00013 
00014 Octave is distributed in the hope that it will be useful, but WITHOUT
00015 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017 for more details.
00018 
00019 You should have received a copy of the GNU General Public License
00020 along with Octave; see the file COPYING.  If not, see
00021 <http://www.gnu.org/licenses/>.
00022 
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #include <cmath>
00030 
00031 #include "file-stat.h"
00032 #include "oct-env.h"
00033 #include "oct-time.h"
00034 
00035 #include "defun-dld.h"
00036 #include "error.h"
00037 #include "ov-struct.h"
00038 
00039 #ifdef HAVE_MAGICK
00040 
00041 #include <Magick++.h>
00042 #include <clocale>
00043 
00044 octave_value_list
00045 read_indexed_images (std::vector<Magick::Image>& imvec,
00046                      const Array<int>& frameidx, bool wantalpha)
00047 {
00048   octave_value_list output;
00049 
00050   int rows = imvec[0].baseRows ();
00051   int columns = imvec[0].baseColumns ();
00052   int nframes = frameidx.length ();
00053 
00054   dim_vector idim = dim_vector ();
00055   idim.resize (4);
00056   idim(0) = rows;
00057   idim(1) = columns;
00058   idim(2) = 1;
00059   idim(3) = nframes;
00060 
00061   Array<int> idx (dim_vector (4, 1));
00062 
00063   Magick::ImageType type = imvec[0].type ();
00064 
00065   unsigned int mapsize = imvec[0].colorMapSize ();
00066   unsigned int i = mapsize;
00067   unsigned int depth = 0;
00068   while (i >>= 1)
00069     depth++;
00070   i = 0;
00071   depth--;
00072   while (depth >>= 1)
00073     i++;
00074   depth = 1 << i;
00075 
00076   switch (depth)
00077     {
00078     case 1:
00079     case 2:
00080     case 4:
00081     case 8:
00082       {
00083         uint8NDArray im = uint8NDArray (idim);
00084 
00085         idx(2) = 0;
00086         for (int frame = 0; frame < nframes; frame++)
00087           {
00088             imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00089 
00090             const Magick::IndexPacket *pix
00091               = imvec[frameidx(frame)].getConstIndexes ();
00092 
00093             i = 0;
00094             idx(3) = frame;
00095 
00096             for (int y = 0; y < rows; y++)
00097               {
00098                 idx(0) = y;
00099                 for (int x = 0; x < columns; x++)
00100                   {
00101                     idx(1) = x;
00102                     im(idx) = static_cast<octave_uint8> (pix[i++]);
00103                   }
00104               }
00105           }
00106 
00107         output(0) = octave_value (im);
00108       }
00109       break;
00110 
00111     case 16:
00112       {
00113         uint16NDArray im = uint16NDArray (idim);
00114 
00115         idx(2) = 0;
00116         for (int frame = 0; frame < nframes; frame++)
00117           {
00118             imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00119 
00120             const Magick::IndexPacket *pix
00121               = imvec[frameidx(frame)].getConstIndexes ();
00122 
00123             i = 0;
00124             idx(3) = frame;
00125 
00126             for (int y = 0; y < rows; y++)
00127               {
00128                 idx(0) = y;
00129                 for (int x = 0; x < columns; x++)
00130                   {
00131                     idx(1) = x;
00132                     im(idx) = static_cast<octave_uint16> (pix[i++]);
00133                   }
00134               }
00135           }
00136 
00137         output(0) = octave_value (im);
00138       }
00139       break;
00140 
00141     default:
00142       error ("__magic_read__: index depths greater than 16-bit are not supported");
00143       return octave_value_list ();
00144     }
00145 
00146   Matrix map = Matrix (mapsize, 3);
00147   Matrix alpha;
00148 
00149   switch (type)
00150     {
00151     case Magick::PaletteMatteType:
00152 #if 0
00153       warning ("palettematte");
00154       Matrix map (mapsize, 3);
00155       Matrix alpha (mapsize, 1);
00156       for (i = 0; i < mapsize; i++)
00157         {
00158           warning ("%d", i);
00159           Magick::ColorRGB c = imvec[0].colorMap (i);
00160           map(i,0) = c.red ();
00161           map(i,1) = c.green ();
00162           map(i,2) = c.blue ();
00163           alpha(i,1) = c.alpha ();
00164         }
00165       break;
00166 #endif
00167 
00168     case Magick::PaletteType:
00169       alpha = Matrix (0, 0);
00170       for (i = 0; i < mapsize; i++)
00171         {
00172           Magick::ColorRGB c = imvec[0].colorMap (i);
00173           map(i,0) = c.red ();
00174           map(i,1) = c.green ();
00175           map(i,2) = c.blue ();
00176         }
00177       break;
00178 
00179     default:
00180       error ("__magick_read__: unsupported indexed image type");
00181       return octave_value_list ();
00182     }
00183 
00184   if (wantalpha)
00185     output(2) = alpha;
00186 
00187   output(1) = map;
00188 
00189   return output;
00190 }
00191 
00192 template <class T>
00193 octave_value_list
00194 read_images (const std::vector<Magick::Image>& imvec,
00195              const Array<int>& frameidx, unsigned int depth)
00196 {
00197   typedef typename T::element_type P;
00198 
00199   octave_value_list retval (3, Matrix ());
00200 
00201   T im;
00202 
00203   int rows = imvec[0].baseRows ();
00204   int columns = imvec[0].baseColumns ();
00205   int nframes = frameidx.length ();
00206 
00207   dim_vector idim = dim_vector ();
00208   idim.resize (4);
00209   idim(0) = rows;
00210   idim(1) = columns;
00211   idim(2) = 1;
00212   idim(3) = nframes;
00213 
00214   Magick::ImageType type = imvec[0].type ();
00215   const int divisor = ((uint64_t (1) << QuantumDepth) - 1) / 
00216                       ((uint64_t (1) << depth) - 1);
00217 
00218   switch (type)
00219     {
00220     case Magick::BilevelType:
00221     case Magick::GrayscaleType:
00222       {
00223         im = T (idim);
00224         P *vec = im.fortran_vec ();
00225 
00226         for (int frame = 0; frame < nframes; frame++)
00227           {
00228             const Magick::PixelPacket *pix
00229               = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00230 
00231             P *rbuf = vec;
00232             for (int y = 0; y < rows; y++)
00233               {
00234                 for (int x = 0; x < columns; x++)
00235                   {
00236                     *rbuf = pix->red / divisor;
00237                     pix++;
00238                     rbuf += rows;
00239                   }
00240                 rbuf -= rows * columns - 1;
00241               }
00242 
00243             // Next frame.
00244             vec += rows * columns * idim(2);
00245           }
00246         }
00247       break;
00248 
00249     case Magick::GrayscaleMatteType:
00250       {
00251         idim(2) = 2;
00252         im = T (idim);
00253         P *vec = im.fortran_vec ();
00254 
00255         for (int frame = 0; frame < nframes; frame++)
00256           {
00257             const Magick::PixelPacket *pix
00258               = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00259 
00260             P *rbuf = vec;
00261             P *obuf = vec + rows * columns;
00262             for (int y = 0; y < rows; y++)
00263               {
00264                 for (int x = 0; x < columns; x++)
00265                   {
00266                     *rbuf = pix->red / divisor;
00267                     *obuf = pix->opacity / divisor;
00268                     pix++;
00269                     rbuf += rows;
00270                     obuf += rows;
00271                   }
00272                 rbuf -= rows * columns - 1;
00273                 obuf -= rows * columns - 1;
00274               }
00275 
00276             // Next frame.
00277             vec += rows * columns * idim(2);
00278           }
00279         }
00280       break;
00281 
00282     case Magick::PaletteType:
00283     case Magick::TrueColorType:
00284       {
00285         idim(2) = 3;
00286         im = T (idim);
00287         P *vec = im.fortran_vec ();
00288 
00289         for (int frame = 0; frame < nframes; frame++)
00290           {
00291             const Magick::PixelPacket *pix
00292               = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00293 
00294             P *rbuf = vec;
00295             P *gbuf = vec + rows * columns;
00296             P *bbuf = vec + rows * columns * 2;
00297             for (int y = 0; y < rows; y++)
00298               {
00299                 for (int x = 0; x < columns; x++)
00300                   {
00301                     *rbuf = pix->red / divisor;
00302                     *gbuf = pix->green / divisor;
00303                     *bbuf = pix->blue / divisor;
00304                     pix++;
00305                     rbuf += rows;
00306                     gbuf += rows;
00307                     bbuf += rows;
00308                   }
00309                 rbuf -= rows * columns - 1;
00310                 gbuf -= rows * columns - 1;
00311                 bbuf -= rows * columns - 1;
00312               }
00313 
00314             // Next frame.
00315             vec += rows * columns * idim(2);
00316           }
00317         }
00318       break;
00319 
00320     case Magick::PaletteMatteType:
00321     case Magick::TrueColorMatteType:
00322     case Magick::ColorSeparationType:
00323       {
00324         idim(2) = 4;
00325         im = T (idim);
00326         P *vec = im.fortran_vec ();
00327 
00328         for (int frame = 0; frame < nframes; frame++)
00329           {
00330             const Magick::PixelPacket *pix
00331               = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
00332 
00333             P *rbuf = vec;
00334             P *gbuf = vec + rows * columns;
00335             P *bbuf = vec + rows * columns * 2;
00336             P *obuf = vec + rows * columns * 3;
00337             for (int y = 0; y < rows; y++)
00338               {
00339                 for (int x = 0; x < columns; x++)
00340                   {
00341                     *rbuf = pix->red / divisor;
00342                     *gbuf = pix->green / divisor;
00343                     *bbuf = pix->blue / divisor;
00344                     *obuf = pix->opacity / divisor;
00345                     pix++;
00346                     rbuf += rows;
00347                     gbuf += rows;
00348                     bbuf += rows;
00349                     obuf += rows;
00350                   }
00351                 rbuf -= rows * columns - 1;
00352                 gbuf -= rows * columns - 1;
00353                 bbuf -= rows * columns - 1;
00354                 obuf -= rows * columns - 1;
00355               }
00356 
00357             // Next frame.
00358             vec += rows * columns * idim(2);
00359           }
00360         }
00361       break;
00362 
00363     default:
00364       error ("__magick_read__: undefined ImageMagick image type");
00365       return retval;
00366     }
00367 
00368   retval(0) = im;
00369 
00370   return retval;
00371 }
00372 
00373 #endif
00374 
00375 static void
00376 maybe_initialize_magick (void)
00377 {
00378 #ifdef HAVE_MAGICK
00379 
00380   static bool initialized = false;
00381 
00382   if (! initialized)
00383     {
00384       // Save the locale as GraphicsMagick might change this (depending on version)
00385       const char *static_locale = setlocale (LC_ALL, NULL);
00386       const std::string locale (static_locale);
00387 
00388       std::string program_name = octave_env::get_program_invocation_name ();
00389 
00390       Magick::InitializeMagick (program_name.c_str ());
00391 
00392       // Restore locale from before GraphicsMagick initialisation
00393       setlocale (LC_ALL, locale.c_str ());
00394 
00395       if (QuantumDepth < 32)
00396         warning ("your version of %s limits images to %d bits per pixel",
00397                  MagickPackageName, QuantumDepth);
00398 
00399       initialized = true;
00400     }
00401 #endif
00402 }
00403 
00404 DEFUN_DLD (__magick_read__, args, nargout,
00405   "-*- texinfo -*-\n\
00406 @deftypefn  {Function File} {@var{m} =} __magick_read__(@var{fname}, @var{index})\n\
00407 @deftypefnx {Function File} {[@var{m}, @var{colormap}] =} __magick_read__(@var{fname}, @var{index})\n\
00408 @deftypefnx {Function File} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__(@var{fname}, @var{index})\n\
00409 Read images with ImageMagick++.  In general you should not be using this\n\
00410 function.  Instead use @code{imread}.\n\
00411 @seealso{imread}\n\
00412 @end deftypefn")
00413 {
00414   octave_value_list output;
00415 
00416 #ifdef HAVE_MAGICK
00417 
00418   maybe_initialize_magick ();
00419 
00420   if (args.length () > 3 || args.length () < 1 || ! args(0).is_string ()
00421       || nargout > 3)
00422     {
00423       print_usage ();
00424       return output;
00425     }
00426 
00427   Array<int> frameidx;
00428   bool all_frames = false;
00429 
00430   if (args.length () == 2 && args(1).is_real_type ())
00431     frameidx = args(1).int_vector_value();
00432   else if (args.length () == 3 && args(1).is_string ()
00433            && args(1).string_value() == "frames")
00434     {
00435       if (args(2).is_string () && args(2).string_value() == "all")
00436         all_frames = true;
00437       else if (args(2).is_real_type ())
00438         frameidx = args(2).int_vector_value();
00439     }
00440   else
00441     {
00442       frameidx = Array<int> (dim_vector (1, 1));
00443       frameidx(0) = 1;
00444     }
00445 
00446   std::vector<Magick::Image> imvec;
00447 
00448   try
00449     {
00450       // Read a file into vector of image objects
00451       Magick::readImages (&imvec, args(0).string_value ());
00452     }
00453   catch (Magick::Warning& w)
00454     {
00455       warning ("Magick++ warning: %s", w.what ());
00456     }
00457   catch (Magick::ErrorCoder& e)
00458     {
00459       warning ("Magick++ coder error: %s", e.what ());
00460     }
00461   catch (Magick::Exception& e)
00462     {
00463       error ("Magick++ exception: %s", e.what ());
00464       return output;
00465     }
00466 
00467   int nframes = imvec.size ();
00468   if (all_frames)
00469     {
00470       frameidx = Array<int> (dim_vector (1, nframes));
00471       for (int i = 0; i < frameidx.length (); i++)
00472         frameidx(i) = i;
00473     }
00474   else
00475     {
00476       for (int i = 0; i < frameidx.length (); i++)
00477         {
00478           frameidx(i) = frameidx(i) - 1;
00479 
00480           if (frameidx(i) >= nframes || frameidx(i) < 0)
00481             {
00482               error ("__magick_read__: invalid INDEX vector");
00483               return output;
00484             }
00485         }
00486     }
00487 
00488   Magick::ClassType klass = imvec[0].classType ();
00489 
00490   if (klass == Magick::PseudoClass && nargout > 1)
00491     output = read_indexed_images (imvec, frameidx, (nargout == 3));
00492   else
00493     {
00494       unsigned int depth = imvec[0].modulusDepth ();
00495       if (depth > 1)
00496         {
00497           --depth;
00498           int i = 1;
00499           while (depth >>= 1)
00500             i++;
00501           depth = 1 << i;
00502         }
00503 
00504       switch (depth)
00505         {
00506         case 1:
00507           output = read_images<boolNDArray> (imvec, frameidx, depth);
00508           break;
00509 
00510         case 2:
00511         case 4:
00512         case 8:
00513           output = read_images<uint8NDArray> (imvec, frameidx, depth) ;
00514           break;
00515 
00516         case 16:
00517           output = read_images<uint16NDArray> (imvec, frameidx, depth);
00518           break;
00519 
00520         case 32:
00521         case 64:
00522         default:
00523           error ("__magick_read__: image depths greater than 16-bit are not supported");
00524         }
00525     }
00526 #else
00527 
00528   error ("imread: image reading capabilities were disabled when Octave was compiled");
00529 
00530 #endif
00531 
00532   return output;
00533 }
00534 
00535 /*
00536 
00537 ## No test needed for internal helper function.
00538 %!assert (1)
00539 
00540 */
00541 
00542 #ifdef HAVE_MAGICK
00543 
00544 static void
00545 jpg_settings (std::vector<Magick::Image>& imvec,
00546               const Octave_map& options,
00547               bool)
00548 {
00549   bool something_set = false;
00550 
00551   // Quality setting
00552   octave_value result;
00553   Octave_map::const_iterator p;
00554   bool found_it = false;
00555 
00556   for (p = options.begin (); p != options.end (); p++)
00557     {
00558       if (options.key (p) == "Quality")
00559         {
00560           found_it = true;
00561           result = options.contents (p).elem (0);
00562           break;
00563         }
00564     }
00565 
00566   if (found_it && (! result.is_empty ()))
00567     {
00568       something_set = true;
00569 
00570       if (result.is_real_type ())
00571         {
00572           int qlev = result.int_value ();
00573 
00574           if (qlev < 0 || qlev > 100)
00575             warning ("warning: Quality setting invalid--use default of 75");
00576           else
00577             {
00578               for (size_t fnum = 0; fnum < imvec.size (); fnum++)
00579                 imvec[fnum].quality (static_cast<unsigned int>(qlev));
00580             }
00581         }
00582       else
00583         warning ("warning: Quality setting invalid--use default of 75");
00584     }
00585 
00586   // Other settings go here
00587 
00588   if (! something_set)
00589     warning ("__magick_write__ warning: all write parameters ignored");
00590 }
00591 
00592 static void
00593 encode_bool_image (std::vector<Magick::Image>& imvec, const octave_value& img)
00594 {
00595   unsigned int nframes = 1;
00596   boolNDArray m = img.bool_array_value ();
00597 
00598   dim_vector dsizes = m.dims ();
00599   if (dsizes.length () == 4)
00600     nframes = dsizes(3);
00601 
00602   Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1));
00603 
00604   octave_idx_type rows = m.rows ();
00605   octave_idx_type columns = m.columns ();
00606 
00607   for (unsigned int ii = 0; ii < nframes; ii++)
00608     {
00609       Magick::Image im(Magick::Geometry (columns, rows), "black");
00610       im.classType (Magick::DirectClass);
00611       im.depth (1);
00612 
00613       for (int y = 0; y < columns; y++)
00614         {
00615           idx(1) = y;
00616 
00617           for (int x = 0; x < rows; x++)
00618             {
00619               if (nframes > 1)
00620                 {
00621                   idx(2) = 0;
00622                   idx(3) = ii;
00623                 }
00624 
00625               idx(0) = x;
00626 
00627               if (m(idx))
00628                 im.pixelColor (y, x, "white");
00629             }
00630         }
00631 
00632       im.quantizeColorSpace (Magick::GRAYColorspace);
00633       im.quantizeColors (2);
00634       im.quantize ();
00635 
00636       imvec.push_back (im);
00637     }
00638 }
00639 
00640 template <class T>
00641 static void
00642 encode_uint_image (std::vector<Magick::Image>& imvec,
00643                    const octave_value& img,
00644                    bool has_map)
00645 {
00646   unsigned int bitdepth = 0;
00647   T m;
00648 
00649   if (img.is_uint8_type ())
00650     {
00651       bitdepth = 8;
00652       m = img.uint8_array_value ();
00653     }
00654   else if (img.is_uint16_type ())
00655     {
00656       bitdepth = 16;
00657       m = img.uint16_array_value ();
00658     }
00659   else
00660     error ("__magick_write__: invalid image class");
00661 
00662   dim_vector dsizes = m.dims ();
00663   unsigned int nframes = 1;
00664   if (dsizes.length () == 4)
00665     nframes = dsizes(3);
00666 
00667   bool is_color = ((dsizes.length () > 2) && (dsizes(2) > 2));
00668   bool has_alpha = (dsizes.length () > 2 && (dsizes(2) == 2 || dsizes(2) == 4));
00669 
00670   Array<octave_idx_type> idx (dim_vector (dsizes.length (), 1));
00671   octave_idx_type rows = m.rows ();
00672   octave_idx_type columns = m.columns ();
00673 
00674   unsigned int div_factor = (1 << bitdepth) - 1;
00675 
00676   for (unsigned int ii = 0; ii < nframes; ii++)
00677     {
00678       Magick::Image im (Magick::Geometry (columns, rows), "black");
00679 
00680       im.depth (bitdepth);
00681 
00682       if (has_map)
00683         im.classType (Magick::PseudoClass);
00684       else
00685         im.classType (Magick::DirectClass);
00686 
00687       if (is_color)
00688         {
00689           if (has_alpha)
00690             im.type (Magick::TrueColorMatteType);
00691           else
00692             im.type (Magick::TrueColorType);
00693 
00694           Magick::ColorRGB c;
00695 
00696           for (int y = 0; y < columns; y++)
00697             {
00698               idx(1) = y;
00699 
00700               for (int x = 0; x < rows; x++)
00701                 {
00702                   idx(0) = x;
00703 
00704                   if (nframes > 1)
00705                     idx(3) = ii;
00706 
00707                   idx(2) = 0;
00708                   c.red (static_cast<double>(m(idx)) / div_factor);
00709 
00710                   idx(2) = 1;
00711                   c.green (static_cast<double>(m(idx)) / div_factor);
00712 
00713                   idx(2) = 2;
00714                   c.blue (static_cast<double>(m(idx)) / div_factor);
00715 
00716                   if (has_alpha)
00717                     {
00718                       idx(2) = 3;
00719                       c.alpha (static_cast<double>(m(idx)) / div_factor);
00720                     }
00721 
00722                   im.pixelColor (y, x, c);
00723                 }
00724             }
00725         }
00726       else
00727         {
00728           if (has_alpha)
00729             im.type (Magick::GrayscaleMatteType);
00730           else
00731             im.type (Magick::GrayscaleType);
00732 
00733           Magick::ColorGray c;
00734 
00735           for (int y = 0; y < columns; y++)
00736             {
00737               idx(1) = y;
00738 
00739               for (int x=0; x < rows; x++)
00740                 {
00741                   idx(0) = x;
00742 
00743                   if (nframes > 1)
00744                     {
00745                       idx(2) = 0;
00746                       idx(3) = ii;
00747                     }
00748 
00749                   if (has_alpha)
00750                     {
00751                       idx(2) = 1;
00752                       c.alpha (static_cast<double>(m(idx)) / div_factor);
00753                       idx(2) = 0;
00754                     }
00755 
00756                   c.shade (static_cast<double>(m(idx)) / div_factor);
00757 
00758                   im.pixelColor (y, x, c);
00759                 }
00760             }
00761 
00762           im.quantizeColorSpace (Magick::GRAYColorspace);
00763           im.quantizeColors (1 << bitdepth);
00764           im.quantize ();
00765         }
00766 
00767       imvec.push_back (im);
00768     }
00769 }
00770 
00771 static void
00772 encode_map (std::vector<Magick::Image>& imvec, const NDArray& cmap)
00773 {
00774   unsigned int mapsize = cmap.dim1 ();
00775 
00776   for (size_t fnum = 0; fnum < imvec.size (); fnum++)
00777     {
00778       imvec[fnum].colorMapSize (mapsize);
00779       imvec[fnum].type (Magick::PaletteType);
00780     }
00781 
00782   for (unsigned int ii = 0; ii < mapsize; ii++)
00783     {
00784       Magick::ColorRGB c (cmap(ii,0), cmap(ii,1), cmap(ii,2));
00785 
00786       // FIXME -- is this case needed?
00787       if (cmap.dim2 () == 4)
00788         c.alpha (cmap(ii,3));
00789 
00790       try
00791         {
00792           for_each (imvec.begin (), imvec.end (),
00793                     Magick::colorMapImage (ii, c));
00794         }
00795       catch (Magick::Warning& w)
00796         {
00797           warning ("Magick++ warning: %s", w.what ());
00798         }
00799       catch (Magick::ErrorCoder& e)
00800         {
00801           warning ("Magick++ coder error: %s", e.what ());
00802         }
00803       catch (Magick::Exception& e)
00804         {
00805           error ("Magick++ exception: %s", e.what ());
00806         }
00807     }
00808 }
00809 
00810 static void
00811 write_image (const std::string& filename, const std::string& fmt,
00812              const octave_value& img,
00813              const octave_value& map = octave_value (),
00814              const octave_value& params = octave_value ())
00815 {
00816   std::vector<Magick::Image> imvec;
00817 
00818   bool has_map = map.is_defined ();
00819 
00820   if (has_map)
00821     {
00822       error ("__magick_write__: direct saving of indexed images not currently supported; use ind2rgb and save converted image");
00823       return;
00824     }
00825 
00826   if (img.is_bool_type ())
00827     encode_bool_image (imvec, img);
00828   else if (img.is_uint8_type ())
00829     encode_uint_image<uint8NDArray> (imvec, img, has_map);
00830   else if (img.is_uint16_type ())
00831     encode_uint_image<uint16NDArray> (imvec, img, has_map);
00832   else
00833     error ("__magick_write__: image type not supported");
00834 
00835   if (! error_state && has_map)
00836     {
00837       NDArray cmap = map.array_value ();
00838 
00839       if (! error_state)
00840         encode_map (imvec, cmap);
00841     }
00842 
00843   if (! error_state && params.is_defined ())
00844     {
00845       Octave_map options = params.map_value ();
00846 
00847       // Insert calls here to handle parameters for various image formats
00848       if (fmt == "jpg" || fmt == "jpeg")
00849         jpg_settings (imvec, options, has_map);
00850       else
00851         warning ("warning: your parameter(s) currently not supported");
00852     }
00853 
00854   try
00855     {
00856       Magick::writeImages (imvec.begin (), imvec.end (), fmt + ":" + filename);
00857     }
00858   catch (Magick::Warning& w)
00859     {
00860       warning ("Magick++ warning: %s", w.what ());
00861     }
00862   catch (Magick::ErrorCoder& e)
00863     {
00864       warning ("Magick++ coder error: %s", e.what ());
00865     }
00866   catch (Magick::Exception& e)
00867     {
00868       error ("Magick++ exception: %s", e.what ());
00869     }
00870 }
00871 
00872 #endif
00873 
00874 DEFUN_DLD (__magick_write__, args, ,
00875   "-*- texinfo -*-\n\
00876 @deftypefn  {Function File} {} __magick_write__(@var{fname}, @var{fmt}, @var{img})\n\
00877 @deftypefnx {Function File} {} __magick_write__(@var{fname}, @var{fmt}, @var{img}, @var{map})\n\
00878 Write images with ImageMagick++.  In general you should not be using this\n\
00879 function.  Instead use @code{imwrite}.\n\
00880 @seealso{imread}\n\
00881 @end deftypefn")
00882 {
00883   octave_value_list retval;
00884 
00885 #ifdef HAVE_MAGICK
00886   maybe_initialize_magick ();
00887 
00888   int nargin = args.length ();
00889 
00890   if (nargin > 2)
00891     {
00892       std::string filename = args(0).string_value ();
00893 
00894       if (! error_state)
00895         {
00896           std::string fmt = args(1).string_value ();
00897 
00898           if (! error_state)
00899             {
00900               if (nargin > 4)
00901                 write_image (filename, fmt, args(2), args(3), args(4));
00902               else if (nargin > 3)
00903                 if (args(3).is_real_type ())
00904                   write_image (filename, fmt, args(2), args(3));
00905                 else
00906                   write_image (filename, fmt, args(2), octave_value(), args(3));
00907               else
00908                 write_image (filename, fmt, args(2));
00909             }
00910           else
00911             error ("__magick_write__: FMT must be string");
00912         }
00913       else
00914         error ("__magick_write__: FNAME must be a string");
00915     }
00916   else
00917     print_usage ();
00918 #else
00919 
00920   error ("__magick_write__: not available in this version of Octave");
00921 
00922 #endif
00923 
00924 return retval;
00925 }
00926 
00927 /*
00928 
00929 ## No test needed for internal helper function.
00930 %!assert (1)
00931 
00932 */
00933 
00934 #ifdef HAVE_MAGICK
00935 
00936 template<class T>
00937 static octave_value
00938 magick_to_octave_value (const T magick)
00939 {
00940   return octave_value (magick);
00941 }
00942 
00943 static octave_value
00944 magick_to_octave_value (const Magick::EndianType magick)
00945 {
00946   switch (magick)
00947     {
00948       case Magick::LSBEndian:
00949         return octave_value ("little-endian");
00950 
00951       case Magick::MSBEndian:
00952         return octave_value ("big-endian");
00953 
00954       default:
00955         return octave_value ("undefined");
00956     }
00957 }
00958 
00959 static octave_value
00960 magick_to_octave_value (const Magick::ResolutionType magick)
00961 {
00962   switch (magick)
00963     {
00964       case Magick::PixelsPerInchResolution:
00965         return octave_value ("pixels per inch");
00966 
00967       case Magick::PixelsPerCentimeterResolution:
00968         return octave_value ("pixels per centimeter");
00969 
00970       default:
00971         return octave_value ("undefined");
00972     }
00973 }
00974 
00975 static octave_value
00976 magick_to_octave_value (const Magick::ImageType magick)
00977 {
00978   switch (magick)
00979     {
00980       case Magick::BilevelType:
00981       case Magick::GrayscaleType:
00982       case Magick::GrayscaleMatteType:
00983         return octave_value ("grayscale");
00984 
00985       case Magick::PaletteType:
00986       case Magick::PaletteMatteType:
00987         return octave_value ("indexed");
00988 
00989       case Magick::TrueColorType:
00990       case Magick::TrueColorMatteType:
00991       case Magick::ColorSeparationType:
00992         return octave_value ("truecolor");
00993 
00994       default:
00995         return octave_value ("undefined");
00996     }
00997 }
00998 
00999 // We put this in a try-block because GraphicsMagick will throw
01000 // exceptions if a parameter isn't present in the current image.
01001 #define GET_PARAM(NAME, OUTNAME) \
01002   try \
01003     { \
01004       info.contents (OUTNAME)(frame,0) = magick_to_octave_value (im.NAME ()); \
01005     } \
01006   catch (Magick::Warning& w) \
01007     { \
01008     }
01009 
01010 #endif
01011 
01012 DEFUN_DLD (__magick_finfo__, args, ,
01013   "-*- texinfo -*-\n\
01014 @deftypefn {Loadable Function} {} __magick_finfo__(@var{fname})\n\
01015 Read image information with GraphicsMagick++.  In general you should\n\
01016 not be using this function.  Instead use @code{imfinfo}.\n\
01017 @seealso{imfinfo, imread}\n\
01018 @end deftypefn")
01019 {
01020   octave_value retval;
01021 
01022 #ifdef HAVE_MAGICK
01023 
01024   maybe_initialize_magick ();
01025 
01026   if (args.length () < 1 || ! args (0).is_string ())
01027     {
01028       print_usage ();
01029       return retval;
01030     }
01031 
01032   const std::string filename = args (0).string_value ();
01033 
01034   try
01035     {
01036       // Read the file.
01037       std::vector<Magick::Image> imvec;
01038       Magick::readImages (&imvec, args(0).string_value ());
01039       int nframes = imvec.size ();
01040 
01041       // Create the right size for the output.
01042 
01043       static const char *fields[] =
01044         {
01045           "Filename",
01046           "FileModDate",
01047           "FileSize",
01048           "Height",
01049           "Width",
01050           "BitDepth",
01051           "Format",
01052           "LongFormat",
01053           "XResolution",
01054           "YResolution",
01055           "TotalColors",
01056           "TileName",
01057           "AnimationDelay",
01058           "AnimationIterations",
01059           "ByteOrder",
01060           "Gamma",
01061           "Matte",
01062           "ModulusDepth",
01063           "Quality",
01064           "QuantizeColors",
01065           "ResolutionUnits",
01066           "ColorType",
01067           "View",
01068           0
01069         };
01070 
01071       Octave_map info (string_vector (fields), dim_vector (nframes, 1));
01072 
01073       file_stat fs (filename);
01074 
01075       std::string filetime;
01076 
01077       if (fs)
01078         {
01079           octave_localtime mtime = fs.mtime ();
01080 
01081           filetime = mtime.strftime ("%e-%b-%Y %H:%M:%S");
01082         }
01083       else
01084         {
01085           std::string msg = fs.error ();
01086 
01087           error ("imfinfo: error reading '%s': %s",
01088                  filename.c_str (), msg.c_str ());
01089 
01090           return retval;
01091         }
01092 
01093       // For each frame in the image (some images contain multiple
01094       // layers, each to be treated like a separate image).
01095       for (int frame = 0; frame < nframes; frame++)
01096         {
01097           Magick::Image im = imvec[frame];
01098 
01099           // Add file name and timestamp.
01100           info.contents ("Filename")(frame,0) = filename;
01101           info.contents ("FileModDate")(frame,0) = filetime;
01102 
01103           // Annoying CamelCase naming is for Matlab compatibility.
01104           GET_PARAM (fileSize, "FileSize")
01105           GET_PARAM (rows, "Height")
01106           GET_PARAM (columns, "Width")
01107           GET_PARAM (depth, "BitDepth")
01108           GET_PARAM (magick, "Format")
01109           GET_PARAM (format, "LongFormat")
01110           GET_PARAM (xResolution, "XResolution")
01111           GET_PARAM (yResolution, "YResolution")
01112           GET_PARAM (totalColors, "TotalColors")
01113           GET_PARAM (tileName, "TileName")
01114           GET_PARAM (animationDelay, "AnimationDelay")
01115           GET_PARAM (animationIterations, "AnimationIterations")
01116           GET_PARAM (endian, "ByteOrder")
01117           GET_PARAM (gamma, "Gamma")
01118           GET_PARAM (matte, "Matte")
01119           GET_PARAM (modulusDepth, "ModulusDepth")
01120           GET_PARAM (quality, "Quality")
01121           GET_PARAM (quantizeColors, "QuantizeColors")
01122           GET_PARAM (resolutionUnits, "ResolutionUnits")
01123           GET_PARAM (type, "ColorType")
01124           GET_PARAM (view, "View")
01125         }
01126 
01127       retval = octave_value (info);
01128     }
01129   catch (Magick::Warning& w)
01130     {
01131       warning ("Magick++ warning: %s", w.what ());
01132     }
01133   catch (Magick::ErrorCoder& e)
01134     {
01135       warning ("Magick++ coder error: %s", e.what ());
01136     }
01137   catch (Magick::Exception& e)
01138     {
01139       error ("Magick++ exception: %s", e.what ());
01140       return retval;
01141     }
01142 
01143 #else
01144 
01145   error ("imfinfo: not available in this version of Octave");
01146 
01147 #endif
01148 
01149   return retval;
01150 }
01151 
01152 /*
01153 
01154 ## No test needed for internal helper function.
01155 %!assert (1)
01156 
01157 */
01158 
01159 #undef GET_PARAM
01160 
01161 // Determine the file formats supported by GraphicsMagick.  This is
01162 // called once at the beginning of imread or imwrite to determine
01163 // exactly which file formats are supported, so error messages can be
01164 // displayed properly.
01165 
01166 DEFUN_DLD (__magick_format_list__, args, ,
01167   "-*- texinfo -*-\n\
01168 @deftypefn {Function File} {} __magick_format_list__ (@var{formats})\n\
01169 Undocumented internal function.\n\
01170 @end deftypefn")
01171 {
01172   octave_value retval;
01173 
01174 #ifdef HAVE_MAGICK
01175   maybe_initialize_magick ();
01176 
01177   std::list<std::string> accepted_formats;
01178 
01179   if (args.length () == 1)
01180     {
01181       Cell c = args (0).cell_value ();
01182 
01183       if (! error_state)
01184         {
01185           for (octave_idx_type i = 0; i < c.nelem (); i++)
01186             {
01187               try
01188                 {
01189                   std::string fmt = c.elem (i).string_value ();
01190 
01191                   Magick::CoderInfo info(fmt);
01192 
01193                   if (info.isReadable () && info.isWritable ())
01194                     accepted_formats.push_back (fmt);
01195                 }
01196               catch (Magick::Exception& e)
01197                 {
01198                   // Do nothing: exception here are simply missing formats.
01199                 }
01200             }
01201         }
01202       else
01203         error ("__magick_format_list__: expecting a cell array of image format names");
01204     }
01205   else
01206     print_usage ();
01207 
01208   retval = Cell (accepted_formats);
01209 
01210 #else
01211 
01212   error ("__magick_format_list__: not available in this version of Octave");
01213 
01214 #endif
01215 
01216   return retval;
01217 }
01218 
01219 /*
01220 
01221 ## No test needed for internal helper function.
01222 %!assert (1)
01223 
01224 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines