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