src/DLD-FUNCTIONS/__magick_read__.cc
author John W. Eaton <jwe@octave.org>
Thu Jul 16 11:56:44 2009 -0400 (2009-07-16)
changeset 9384 44300eb51817
parent 9275 86f475d5e7d1
child 9387 b308b2e12f04
permissions -rw-r--r--
graphics.cc (get_array_limits): require min_pos value to be greater than zero
     1 /*
     2 
     3 Copyright (C) 2002, 2009 Andy Adler
     4 Copyright (C) 2008 Thomas L. Scofield
     5 
     6 This file is part of Octave.
     7 
     8 Octave is free software; you can redistribute it and/or modify it
     9 under the terms of the GNU General Public License as published by the
    10 Free Software Foundation; either version 3 of the License, or (at your
    11 option) any later version.
    12 
    13 Octave is distributed in the hope that it will be useful, but WITHOUT
    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    16 for more details.
    17 
    18 You should have received a copy of the GNU General Public License
    19 along with Octave; see the file COPYING.  If not, see
    20 <http://www.gnu.org/licenses/>.
    21 
    22 */
    23 
    24 #ifdef HAVE_CONFIG_H
    25 #include <config.h>
    26 #endif
    27 
    28 #include <cmath>
    29 
    30 #include "defun-dld.h"
    31 #include "error.h"
    32 #include "ov-struct.h"
    33 
    34 #ifdef HAVE_MAGICK
    35 
    36 #include <GraphicsMagick/Magick++.h>
    37 
    38 unsigned int
    39 scale_quantum_to_depth (const Magick::Quantum& quantum, unsigned int depth)
    40 {
    41   return (static_cast<unsigned int> (static_cast<double> (quantum)
    42                                      / MaxRGB * ((1 << depth) - 1)));
    43 }
    44 
    45 octave_value_list
    46 read_indexed_images (std::vector<Magick::Image>& imvec,
    47                      const Array<int>& frameidx, bool wantalpha)
    48 {
    49   octave_value_list output;
    50 
    51   int rows = imvec[0].baseRows ();
    52   int columns = imvec[0].baseColumns ();
    53   int nframes = frameidx.length ();
    54 
    55   dim_vector idim = dim_vector ();
    56   idim.resize (4);
    57   idim(0) = rows;
    58   idim(1) = columns;
    59   idim(2) = 1;
    60   idim(3) = nframes;
    61 
    62   Array<int> idx (dim_vector (4));
    63 
    64   Magick::ImageType type = imvec[0].type ();
    65 
    66   unsigned int mapsize = imvec[0].colorMapSize ();
    67   unsigned int i = mapsize;
    68   unsigned int depth = 0;
    69   while (i >>= 1)
    70     depth++;
    71   i = 0;
    72   depth--;
    73   while (depth >>= 1)
    74     i++;
    75   depth = 1 << i;
    76 
    77   switch (depth)
    78     {
    79     case 1:
    80     case 2:
    81     case 4:
    82     case 8:
    83       {
    84         uint8NDArray im = uint8NDArray (idim);
    85 
    86         idx(2) = 0;
    87         for (int frame = 0; frame < nframes; frame++)
    88           {
    89             imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
    90 
    91             const Magick::IndexPacket *pix
    92               = imvec[frameidx(frame)].getConstIndexes ();
    93 
    94             i = 0;
    95             idx(3) = frame;
    96 
    97             for (int y = 0; y < rows; y++)
    98               {
    99                 idx(0) = y;
   100                 for (int x = 0; x < columns; x++)
   101                   {
   102                     idx(1) = x;
   103                     im(idx) = static_cast<octave_uint8> (pix[i++]);
   104                   }
   105               }
   106           }
   107         im.chop_trailing_singletons ();
   108         output(0) = octave_value (im);
   109       }
   110       break;
   111 
   112     case 16:
   113       {
   114         uint16NDArray im = uint16NDArray (idim);
   115 
   116         idx(2) = 0;
   117         for (int frame = 0; frame < nframes; frame++)
   118           {
   119             imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
   120 
   121             const Magick::IndexPacket *pix
   122               = imvec[frameidx(frame)].getConstIndexes ();
   123 
   124             i = 0;
   125             idx(3) = frame;
   126 
   127             for (int y = 0; y < rows; y++)
   128               {
   129                 idx(0) = y;
   130                 for (int x = 0; x < columns; x++)
   131                   {
   132                     idx(1) = x;
   133                     im(idx) = static_cast<octave_uint16> (pix[i++]);
   134                   }
   135               }
   136           }
   137         im.chop_trailing_singletons ();
   138         output(0) = octave_value (im);
   139       }
   140       break;
   141 
   142     default:
   143       error ("__magic_read__: index depths bigger than 16-bit not supported");
   144       return octave_value_list ();
   145     }
   146 
   147   Matrix map = Matrix (mapsize, 3);
   148   Matrix alpha;
   149 
   150   switch (type)
   151     {
   152     case Magick::PaletteMatteType:
   153 #if 0
   154       warning ("palettematte");
   155       Matrix map (mapsize, 3);
   156       Matrix alpha (mapsize, 1);
   157       for (i = 0; i < mapsize; i++)
   158         {
   159           warning ("%d", i);
   160           Magick::ColorRGB c = imvec[0].colorMap (i);
   161           map(i,0) = c.red ();
   162           map(i,1) = c.green ();
   163           map(i,2) = c.blue ();
   164           alpha(i,1) = c.alpha ();
   165         }
   166       break;
   167 #endif
   168 
   169     case Magick::PaletteType:
   170       alpha = Matrix (0, 0);
   171       for (i = 0; i < mapsize; i++)
   172         {
   173           Magick::ColorRGB c = imvec[0].colorMap (i);
   174           map(i,0) = c.red ();
   175           map(i,1) = c.green ();
   176           map(i,2) = c.blue ();
   177         }
   178       break;
   179 
   180     default:
   181       error ("__magick_read__: unsupported indexed image type");
   182       return octave_value_list ();
   183     }
   184 
   185   if (wantalpha)
   186     output(2) = alpha;
   187 
   188   output(1) = map;
   189 
   190   return output;
   191 }
   192 
   193 template <class T>
   194 octave_value_list
   195 read_images (const std::vector<Magick::Image>& imvec,
   196              const Array<int>& frameidx, unsigned int depth)
   197 {
   198   octave_value_list retval (3, Matrix ());
   199 
   200   T im;
   201 
   202   int rows = imvec[0].baseRows ();
   203   int columns = imvec[0].baseColumns ();
   204   int nframes = frameidx.length ();
   205 
   206   dim_vector idim = dim_vector ();
   207   idim.resize (4);
   208   idim(0) = rows;
   209   idim(1) = columns;
   210   idim(2) = 1;
   211   idim(3) = nframes;
   212 
   213   Array<int> idx (dim_vector (4));
   214 
   215   Magick::ImageType type = imvec[0].type ();
   216 
   217   switch (type)
   218     {
   219     case Magick::BilevelType:
   220     case Magick::GrayscaleType:
   221       im = T (idim);
   222       for (int frame = 0; frame < nframes; frame++)
   223         {
   224           const Magick::PixelPacket *pix
   225             = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
   226 
   227           int i = 0;
   228           idx(2) = 0;
   229           idx(3) = frame;
   230 
   231           for (int y = 0; y < rows; y++)
   232             {
   233               idx(0) = y;
   234               for (int x = 0; x < columns; x++)
   235                 {
   236                   idx(1) = x;
   237                   im(idx) = scale_quantum_to_depth (pix[i++].red, depth);
   238                 }
   239             }
   240         }
   241       break;
   242 
   243     case Magick::GrayscaleMatteType:
   244       idim(2) = 2;
   245       im = T (idim);
   246       for (int frame = 0; frame < nframes; frame++)
   247         {
   248           const Magick::PixelPacket *pix
   249             = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
   250 
   251           int i = 0;
   252           idx(3) = frame;
   253 
   254           for (int y = 0; y < rows; y++)
   255             {
   256               idx(0) = y;
   257               for (int x = 0; x < columns; x++)
   258                 {
   259                   idx(1) = x;
   260                   idx(2) = 0;
   261                   im(idx) = scale_quantum_to_depth (pix[i].red, depth);
   262                   idx(2) = 1;
   263                   im(idx) = scale_quantum_to_depth (pix[i].opacity, depth);
   264                   i++;
   265                 }
   266             }
   267         }
   268       break;
   269 
   270     case Magick::PaletteType:
   271     case Magick::TrueColorType:
   272       idim(2) = 3;
   273       im = T (idim);
   274       for (int frame = 0; frame < nframes; frame++)
   275         {
   276           const Magick::PixelPacket *pix
   277             = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
   278 
   279           int i = 0;
   280           idx(3) = frame;
   281 
   282           for (int y = 0; y < rows; y++)
   283             {
   284               idx(0) = y;
   285               for (int x = 0; x < columns; x++)
   286                 {
   287                   idx(1) = x;
   288                   idx(2) = 0;
   289                   im(idx) = scale_quantum_to_depth (pix[i].red, depth);
   290                   idx(2) = 1;
   291                   im(idx) = scale_quantum_to_depth (pix[i].green, depth);
   292                   idx(2) = 2;
   293                   im(idx) = scale_quantum_to_depth (pix[i].blue, depth);
   294                   i++;
   295                 }
   296             }
   297         }
   298       break;
   299 
   300     case Magick::PaletteMatteType:
   301     case Magick::TrueColorMatteType:
   302     case Magick::ColorSeparationType:
   303       idim(2) = 4;
   304       im = T (idim);
   305       for (int frame = 0; frame < nframes; frame++)
   306         {
   307           const Magick::PixelPacket *pix
   308             = imvec[frameidx(frame)].getConstPixels (0, 0, columns, rows);
   309 
   310           int i = 0;
   311           idx(3) = frame;
   312 
   313           for (int y = 0; y < rows; y++)
   314             {
   315               idx(0) = y;
   316               for (int x = 0; x < columns; x++)
   317                 {
   318                   idx(1) = x;
   319                   idx(2) = 0;
   320                   im(idx) = scale_quantum_to_depth (pix[i].red, depth);
   321                   idx(2) = 1;
   322                   im(idx) = scale_quantum_to_depth (pix[i].green, depth);
   323                   idx(2) = 2;
   324                   im(idx) = scale_quantum_to_depth (pix[i].blue, depth);
   325                   idx(2) = 3;
   326                   im(idx) = scale_quantum_to_depth (pix[i].opacity, depth);
   327                   i++;
   328                 }
   329             }
   330         }
   331       break;
   332 
   333     default:
   334       error ("__magick_read__: undefined ImageMagick image type");
   335       return retval;
   336     }
   337 
   338   im.chop_trailing_singletons ();
   339 
   340   retval(0) = im;
   341 
   342   return retval;
   343 }
   344 
   345 #endif
   346 
   347 DEFUN_DLD (magick_read, args, nargout,
   348   "-*- texinfo -*-\n\
   349 @deftypefn {Function File} {@var{m} =} __magick_read__(@var{fname}, @var{index})\n\
   350 @deftypefnx{Function File} {[@var{m}, @var{colormap}] =} __magick_read__(@var{fname}, @var{index})\n\
   351 @deftypefnx{Function File} {[@var{m}, @var{colormap}, @var{alpha}] =} __magick_read__(@var{fname}, @var{index})\n\
   352 Read images with ImageMagick++.  In general you should not be using this function.\n\
   353 Instead you should use @code{imread}.\n\
   354 @seealso{imread}\n\
   355 @end deftypefn")
   356 {
   357   octave_value_list output;
   358 
   359 #ifdef HAVE_MAGICK
   360 
   361   if (args.length () > 2 || args.length () < 1 || ! args(0).is_string ()
   362       || nargout > 3)
   363     {
   364       print_usage ();
   365       return output;
   366     }
   367 
   368   Array<int> frameidx;
   369 
   370   if (args.length () == 2 && args(1).is_real_type ())
   371     frameidx = args(1).int_vector_value();
   372   else
   373     {
   374       frameidx = Array<int> (1);
   375       frameidx(0) = 1;
   376     }
   377 
   378   std::vector<Magick::Image> imvec;
   379 
   380   try
   381     {
   382       // Read a file into vector of image objects
   383       Magick::readImages (&imvec, args(0).string_value ());
   384     }
   385   catch (Magick::Warning& w)
   386     {
   387       warning ("Magick++ warning: %s", w.what ());
   388     }
   389   catch (Magick::ErrorCoder& e)
   390     {
   391       warning ("Magick++ coder error: %s", e.what ());
   392     }
   393   catch (Magick::Exception& e)
   394     {
   395       error ("Magick++ exception: %s", e.what ());
   396       return output;
   397     }
   398 
   399   for (int i = 0; i < frameidx.length(); i++)
   400     {
   401       frameidx(i) = frameidx(i) - 1;
   402 
   403       int nframes = imvec.size ();
   404 
   405       if (frameidx(i) >= nframes || frameidx(i) < 0)
   406         {
   407           error ("__magick_read__: invalid index vector");
   408           return output;
   409         }
   410     }
   411 
   412   Magick::ClassType klass = imvec[0].classType ();
   413 
   414   if (klass == Magick::PseudoClass && nargout > 1)
   415     output = read_indexed_images (imvec, frameidx, (nargout == 3));
   416   else
   417     {
   418       unsigned int depth = imvec[0].modulusDepth ();
   419       int i = 0;
   420       while (depth >>= 1)
   421         i++;
   422       depth = 1 << i;
   423 
   424       switch (depth)
   425         {
   426         case 1:
   427           output = read_images<boolNDArray> (imvec, frameidx, depth);
   428           break;
   429 
   430         case 2:
   431         case 4:
   432         case 8:
   433           output = read_images<uint8NDArray> (imvec, frameidx, depth) ;
   434           break;
   435 
   436         case 16:
   437           output = read_images<uint16NDArray> (imvec, frameidx, depth);
   438           break;
   439 
   440         case 32:
   441         case 64:
   442         default:
   443           error ("__magick_read__: image depths bigger than 16-bit not supported");
   444         }
   445     }
   446 #else
   447 
   448   error ("__magick_read__: not available in this version of Octave");
   449 
   450 #endif
   451 
   452   return output;
   453 }
   454 
   455 #ifdef HAVE_MAGICK
   456 
   457 static void
   458 jpg_settings (std::vector<Magick::Image>& imvec,
   459               const Octave_map& options,
   460               bool)
   461 {
   462   int nframes = static_cast<int>(imvec.size ());
   463   bool something_set = 0;
   464 
   465   // Quality setting
   466   octave_value result;
   467   Octave_map::const_iterator p;
   468   bool found_it = 0;
   469   for (p = options.begin (); p != options.end (); p++)
   470     if (options.key (p) == "Quality")
   471       {
   472         found_it = 1;
   473         result = options.contents (p).elem (0);
   474         break;
   475       }
   476   if (found_it && (! result.is_empty ()))
   477     {
   478       something_set = 1;
   479       if (result.is_real_type ())
   480         {
   481           int qlev = static_cast<int>(result.int_value ());
   482           if (qlev < 0 || qlev > 100)
   483             warning ("warning: Quality setting invalid--use default of 75");
   484           else
   485             for (int fnum = 0; fnum < nframes; fnum++)
   486               imvec[fnum].quality (static_cast<unsigned int>(qlev));
   487         }
   488       else
   489         warning ("warning: Quality setting invalid--use default of 75");
   490     }
   491 
   492   // Other settings go here
   493 
   494   if (! something_set)
   495     warning ("__magick_write__ warning: All write parameters ignored.");
   496 }
   497 
   498 static void
   499 encode_bool_image (std::vector<Magick::Image>& imvec, const octave_value& img)
   500 {
   501   unsigned int nframes = 1;
   502   boolNDArray m = img.bool_array_value ();
   503 
   504   dim_vector dsizes = m.dims ();
   505   if (dsizes.length () == 4)
   506     nframes = dsizes(3);
   507 
   508   Array<octave_idx_type> idx (dsizes.length ());
   509 
   510   octave_idx_type rows = m.rows ();
   511   octave_idx_type columns = m.columns ();
   512 
   513   for (unsigned int ii = 0; ii < nframes; ii++)
   514     {
   515       Magick::Image im(Magick::Geometry (columns, rows), "black");
   516       im.classType (Magick::DirectClass);
   517       im.depth (1);
   518 
   519       for (int y=0; y < columns; y++)
   520         {
   521           idx(1) = y;
   522           for (int x=0; x < rows; x++)
   523             {
   524               if (nframes > 1)
   525                 {
   526                   idx(2) = 0;
   527                   idx(3) = ii;
   528                 }
   529               idx(0) = x;
   530               if (m(idx))
   531                 im.pixelColor (y, x, "white");
   532             }
   533         }
   534       imvec.push_back (im);
   535     }
   536 }
   537 
   538 template <class T>
   539 static void
   540 encode_uint_image (std::vector<Magick::Image>& imvec,
   541                    const octave_value& img,
   542                    bool has_map)
   543 {
   544   unsigned int bitdepth = 0;
   545   T m;
   546 
   547   if (img.is_uint8_type ())
   548     {
   549       bitdepth = 8;
   550       m = img.uint8_array_value ();
   551     }
   552   else if (img.is_uint16_type ())
   553     {
   554       bitdepth = 16;
   555       m = img.uint16_array_value ();
   556     }
   557   else
   558     error ("__magick_write__: invalid image class");
   559 
   560   dim_vector dsizes = m.dims ();
   561   unsigned int nframes = 1;
   562   if (dsizes.length () == 4)
   563     nframes = dsizes(3);
   564   bool is_color = ((dsizes.length () > 2) && (dsizes(2) > 2));
   565   bool has_alpha = (dsizes.length () > 2 && (dsizes(2) == 2 || dsizes(2) == 4));
   566 
   567   Array<octave_idx_type> idx (dsizes.length ());
   568   octave_idx_type rows = m.rows ();
   569   octave_idx_type columns = m.columns ();
   570 
   571   // FIXME -- maybe simply using bit shifting would be better?
   572   unsigned int div_factor = pow (2.0, static_cast<int> (bitdepth)) - 1;
   573 
   574   for (unsigned int ii = 0; ii < nframes; ii++)
   575     {
   576       Magick::Image im(Magick::Geometry (columns, rows), "black");
   577       im.depth (bitdepth);
   578       if (has_map)
   579         im.classType (Magick::PseudoClass);
   580       else
   581         im.classType (Magick::DirectClass);
   582 
   583       if (is_color)
   584         {
   585           if (has_alpha)
   586             im.type (Magick::TrueColorMatteType);
   587           else
   588             im.type (Magick::TrueColorType);
   589 
   590           Magick::ColorRGB c;
   591           for (int y=0; y < columns; y++)
   592             {
   593               idx(1) = y;
   594               for (int x=0; x < rows; x++)
   595                 {
   596                   idx(0) = x;
   597                   if (nframes > 1)
   598                     idx(3) = ii;
   599 
   600                   idx(2) = 0;
   601                   c.red (static_cast<double>(m(idx)) / div_factor);
   602                   idx(2) = 1;
   603                   c.green (static_cast<double>(m(idx)) / div_factor);
   604                   idx(2) = 2;
   605                   c.blue (static_cast<double>(m(idx)) / div_factor);
   606 
   607                   if (has_alpha)
   608                     {
   609                       idx(2) = 3;
   610                       c.alpha (static_cast<double>(m(idx)) / div_factor);
   611                     }
   612                   im.pixelColor (y, x, c);
   613                 }
   614             }
   615         }
   616       else
   617         {
   618           if (has_alpha)
   619             im.type (Magick::GrayscaleMatteType);
   620           else
   621             im.type (Magick::GrayscaleType);
   622 
   623           Magick::ColorGray c;
   624 
   625           for (int y=0; y < columns; y++)
   626             {
   627               idx(1) = y;
   628               for (int x=0; x < rows; x++)
   629                 {
   630                   idx(0) = x;
   631                   if (nframes > 1)
   632                     {
   633                       idx(2) = 0;
   634                       idx(3) = ii;
   635                     }
   636                   if (has_alpha)
   637                     {
   638                       idx(2) = 1;
   639                       c.alpha (static_cast<double>(m(idx)) / div_factor);
   640                       idx(2) = 0;
   641                     }
   642 
   643                   c.shade (static_cast<double>(m(idx)) / div_factor);
   644                   im.pixelColor (y, x, c);
   645                 }
   646             }
   647         }
   648       imvec.push_back (im);
   649     }
   650 }
   651 
   652 static void
   653 encode_map (std::vector<Magick::Image>& imvec, const NDArray& cmap)
   654 {
   655   unsigned int mapsize = cmap.dim1 ();
   656   int nframes = static_cast<int>(imvec.size ());
   657 
   658   for (int fnum = 0; fnum < nframes; fnum++)
   659     {
   660       imvec[fnum].colorMapSize (mapsize);
   661       imvec[fnum].type (Magick::PaletteType);
   662     }
   663 
   664   for (unsigned int ii = 0; ii < mapsize; ii++)
   665     {
   666       Magick::ColorRGB c (cmap(ii,0), cmap(ii,1), cmap(ii,2));
   667 
   668       // FIXME -- is this case needed?
   669       if (cmap.dim2 () == 4)
   670         c.alpha (cmap(ii,3));
   671 
   672       try
   673         {
   674           for_each (imvec.begin (), imvec.end (),
   675                     Magick::colorMapImage (ii, c));
   676         }
   677       catch (Magick::Warning& w)
   678         {
   679           warning ("Magick++ warning: %s", w.what ());
   680         }
   681       catch (Magick::ErrorCoder& e)
   682         {
   683           warning ("Magick++ coder error: %s", e.what ());
   684         }
   685       catch (Magick::Exception& e)
   686         {
   687           error ("Magick++ exception: %s", e.what ());
   688         }
   689     }
   690 }
   691 
   692 static void
   693 write_image (const std::string& filename, const std::string& fmt,
   694              const octave_value& img,
   695              const octave_value& map = octave_value (),
   696              const octave_value& params = octave_value ())
   697 {
   698   std::vector<Magick::Image> imvec;
   699 
   700   bool has_map = map.is_defined ();
   701 
   702   if (has_map)
   703     {
   704       error ("__magick_write__: direct saving of indexed images not currently supported; use ind2rgb and save converted image");
   705       return;
   706     }
   707 
   708   if (img.is_bool_type ())
   709     encode_bool_image (imvec, img);
   710   else if (img.is_uint8_type ())
   711     encode_uint_image<uint8NDArray> (imvec, img, has_map);
   712   else if (img.is_uint16_type ())
   713     encode_uint_image<uint16NDArray> (imvec, img, has_map);
   714   else
   715     error ("__magick_write__: image type not supported");
   716 
   717   if (! error_state && has_map)
   718     {
   719       NDArray cmap = map.array_value ();
   720 
   721       if (! error_state)
   722         encode_map (imvec, cmap);
   723     }
   724 
   725   if (! error_state && params.is_defined ())
   726     {
   727       Octave_map options = params.map_value ();
   728 
   729       // Insert calls here to handle parameters for various image formats
   730       if (fmt == "jpg" || fmt == "jpeg")
   731         jpg_settings (imvec, options, has_map);
   732       else
   733         warning ("warning: your parameter(s) currently not supported");
   734     }
   735 
   736   try
   737     {
   738       Magick::writeImages (imvec.begin (), imvec.end (), filename);
   739     }
   740   catch (Magick::Warning& w)
   741     {
   742       warning ("Magick++ warning: %s", w.what ());
   743     }
   744   catch (Magick::ErrorCoder& e)
   745     {
   746       warning ("Magick++ coder error: %s", e.what ());
   747     }
   748   catch (Magick::Exception& e)
   749     {
   750       error ("Magick++ exception: %s", e.what ());
   751     }
   752 }
   753 
   754 #endif
   755 
   756 DEFUN_DLD (magick_write, args, ,
   757   "-*- texinfo -*-\n\
   758 @deftypefn {Function File} {} __magick_write__(@var{fname}, @var{fmt}, @var{img})\n\
   759 @deftypefnx {Function File} {} __magick_write__(@var{fname}, @var{fmt}, @var{img}, @var{map})\n\
   760 Write images with ImageMagick++.  In general you should not be using this function.\n\
   761 Instead you should use @code{imwrite}.\n\
   762 @seealso{imread}\n\
   763 @end deftypefn")
   764 {
   765   octave_value_list retval;
   766 
   767 #ifdef HAVE_MAGICK
   768   int nargin = args.length ();
   769 
   770   if (nargin > 2)
   771     {
   772       std::string filename = args(0).string_value ();
   773 
   774       if (! error_state)
   775         {
   776           std::string fmt = args(1).string_value ();
   777 
   778           if (! error_state)
   779             {
   780               if (nargin > 4)
   781                 write_image (filename, fmt, args(2), args(3), args(4));
   782               else if (nargin > 3)
   783                 if (args(3).is_real_type ())
   784                   write_image (filename, fmt, args(2), args(3));
   785                 else
   786                   write_image (filename, fmt, args(2), octave_value(), args(3));
   787               else
   788                 write_image (filename, fmt, args(2));
   789             }
   790           else
   791             error ("__magick_write__: expecting format as second argument");
   792         }
   793       else
   794         error ("__magick_write__: expecting filename as first argument");
   795     }
   796   else
   797     print_usage ();
   798 #else
   799 
   800   error ("__magick_write__: not available in this version of Octave");
   801 
   802 #endif
   803 
   804 return retval;
   805 }
   806 
   807 #ifdef HAVE_MAGICK
   808 
   809 template<class T>
   810 static octave_value
   811 magick_to_octave_value (const T magick)
   812 {
   813   return octave_value (magick);
   814 }
   815 
   816 static octave_value
   817 magick_to_octave_value (const Magick::EndianType magick)
   818 {
   819   switch (magick)
   820     {
   821       case Magick::LSBEndian:
   822         return octave_value ("little-endian");
   823 
   824       case Magick::MSBEndian:
   825         return octave_value ("big-endian");
   826 
   827       default:
   828         return octave_value ("undefined");
   829     }
   830 }
   831 
   832 static octave_value
   833 magick_to_octave_value (const Magick::ResolutionType magick)
   834 {
   835   switch (magick)
   836     {
   837       case Magick::PixelsPerInchResolution:
   838         return octave_value ("pixels per inch");
   839 
   840       case Magick::PixelsPerCentimeterResolution:
   841         return octave_value ("pixels per centimeter");
   842 
   843       default:
   844         return octave_value ("undefined");
   845     }
   846 }
   847 
   848 static octave_value
   849 magick_to_octave_value (const Magick::ImageType magick)
   850 {
   851   switch (magick)
   852     {
   853       case Magick::BilevelType:
   854       case Magick::GrayscaleType:
   855       case Magick::GrayscaleMatteType:
   856         return octave_value ("grayscale");
   857 
   858       case Magick::PaletteType:
   859       case Magick::PaletteMatteType:
   860         return octave_value ("indexed");
   861 
   862       case Magick::TrueColorType:
   863       case Magick::TrueColorMatteType:
   864       case Magick::ColorSeparationType:
   865         return octave_value ("truecolor");
   866 
   867       default:
   868         return octave_value ("undefined");
   869     }
   870 }
   871 
   872 // We put this in a try-block because GraphicsMagick will throw
   873 // exceptions if a parameter isn't present in the current image.
   874 #define GET_PARAM(NAME, OUTNAME) \
   875   try \
   876     { \
   877       st.assign (OUTNAME, magick_to_octave_value (im.NAME ())); \
   878     } \
   879   catch (Magick::Warning& w) \
   880     { \
   881     }
   882 
   883 #endif
   884 
   885 DEFUN_DLD (magick_finfo, args, ,
   886   "-*- texinfo -*-\n\
   887 @deftypefn {Loadable File} {} __magick_finfo__(@var{fname})\n\
   888 Read image information with GraphicsMagick++.  In general you should\n\
   889 not be using this function.  Instead you should use @code{imfinfo}.\n\
   890 @seealso{imfinfo, imread}\n\
   891 @end deftypefn")
   892 {
   893   octave_value_list output;
   894 
   895 #ifdef HAVE_MAGICK
   896 
   897   if (args.length () < 1 || ! args (0).is_string ())
   898     {
   899       print_usage ();
   900       return output;
   901     }
   902 
   903   const std::string filename = args (0).string_value ();
   904 
   905   try
   906     {
   907       // Read the file.
   908       Magick::Image im;
   909       im.read (filename);
   910       
   911       // Read properties.
   912       Octave_map st;
   913       st.assign ("Filename", filename);
   914       
   915       // Annoying CamelCase naming is for Matlab compatibility.
   916       GET_PARAM (fileSize, "FileSize")
   917       GET_PARAM (rows, "Height")
   918       GET_PARAM (columns, "Width")
   919       GET_PARAM (depth, "BitDepth")
   920       GET_PARAM (magick, "Format")
   921       GET_PARAM (format, "LongFormat")
   922       GET_PARAM (xResolution, "XResolution")
   923       GET_PARAM (yResolution, "YResolution")
   924       GET_PARAM (totalColors, "TotalColors")
   925       GET_PARAM (tileName, "TileName")
   926       GET_PARAM (animationDelay, "AnimationDelay")
   927       GET_PARAM (animationIterations, "AnimationIterations")
   928       GET_PARAM (endian, "ByteOrder")
   929       GET_PARAM (gamma, "Gamma")
   930       GET_PARAM (matte, "Matte")
   931       GET_PARAM (modulusDepth, "ModulusDepth")
   932       GET_PARAM (quality, "Quality")
   933       GET_PARAM (quantizeColors, "QuantizeColors")
   934       GET_PARAM (resolutionUnits, "ResolutionUnits")
   935       GET_PARAM (type, "ColorType")
   936       GET_PARAM (view, "View")
   937         
   938       output (0) = st;
   939     }
   940   catch (Magick::Warning& w)
   941     {
   942       warning ("Magick++ warning: %s", w.what ());
   943     }
   944   catch (Magick::ErrorCoder& e)
   945     {
   946       warning ("Magick++ coder error: %s", e.what ());
   947     }
   948   catch (Magick::Exception& e)
   949     {
   950       error ("Magick++ exception: %s", e.what ());
   951       return output;
   952     }
   953 
   954 #else
   955 
   956   error ("imfinfo: not available in this version of Octave");
   957 
   958 #endif
   959 
   960   return output;
   961 }
   962 
   963 #undef GET_PARAM
   964       
   965 
   966 /*
   967 ;;; Local Variables: ***
   968 ;;; mode: C++ ***
   969 ;;; indent-tabs-mode: nil ***
   970 ;;; End: ***
   971 */