netpbm.cpp 17 KB
Newer Older
André Anjos's avatar
André Anjos committed
1
2
3
4
/**
 * @file io/cxx/ImageNetpbmFile.cc
 * @date Tue Oct 9 18:13:00 2012 +0200
 * @author Laurent El Shafey <laurent.el-shafey@idiap.ch>
Manuel Günther's avatar
Manuel Günther committed
5
 * @author Manuel Gunther <siebenkopf@googlemail.com>
André Anjos's avatar
André Anjos committed
6
7
8
9
10
 *
 * @brief Implements an image format reader/writer using libnetpbm.
 * This codec is only able to work with 2D and 3D input.
 *
 * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland
Manuel Günther's avatar
Manuel Günther committed
11
 * Copyright (c) 2016, Regents of the University of Colorado on behalf of the University of Colorado Colorado Springs.
André Anjos's avatar
André Anjos committed
12
13
14
15
16
17
18
19
20
21
 */

#include <boost/filesystem.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <string>

Manuel Günther's avatar
Manuel Günther committed
22
#include <bob.io.image/netpbm.h>
23

André Anjos's avatar
André Anjos committed
24
extern "C" {
25
#include "pnmio.h"
André Anjos's avatar
André Anjos committed
26
27
}

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
typedef unsigned long sample;

struct pam {
/* This structure describes an open PAM image file.  It consists
   entirely of information that belongs in the header of a PAM image
   and filesystem information.  It does not contain any state
   information about the processing of that image.

   This is not considered to be an opaque object.  The user of Netbpm
   libraries is free to access and set any of these fields whenever
   appropriate.  The structure exists to make coding of function calls
   easy.
*/

    /* 'size' and 'len' are necessary in order to provide forward and
       backward compatibility between library functions and calling programs
       as this structure grows.
       */
    unsigned int size;
        /* The storage size of this entire structure, in bytes */
    unsigned int len;
        /* The length, in bytes, of the information in this structure.
           The information starts in the first byte and is contiguous.
           This cannot be greater than 'size'
           */
    FILE *file;
    int format;
        /* The format code of the raw image.  This is PAM_FORMAT
           unless the PAM image is really a view of a PBM, PGM, or PPM
           image.  Then it's PBM_FORMAT, RPBM_FORMAT, etc.
           */
    unsigned int plainformat;
        /* Logical:  the format above is a plain (text) format as opposed
           to a raw (binary) format.  This is entirely redundant with the
           'format' member and exists as a separate member only for
           computational speed.
        */
    int height;  /* Height of image in rows */
    int width;
        /* Width of image in number of columns (tuples per row) */
    unsigned int depth;
        /* Depth of image (number of samples in each tuple). */
    sample maxval;  /* Maximum defined value for a sample */
    unsigned int bytes_per_sample;
        /* Number of bytes used to represent each sample in the image file.
           Note that this is strictly a function of 'maxval'.  It is in a
           a separate member for computational speed.
           */
    char tuple_type[256];
        /* The tuple type string from the image header.  Netpbm does
           not define any values for this except the following, which are
           used for a PAM image which is really a view of a PBM, PGM,
           or PPM image:  PAM_PBM_TUPLETYPE, PAM_PGM_TUPLETYPE,
           PAM_PPM_TUPLETYPE.
           */
};


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/* File open/close that handles "-" as stdin/stdout and checks errors. */

FILE*
pm_openr(const char * const name) {
    FILE* f;

    if (strcmp(name, "-") == 0)
        f = stdin;
    else {
#ifndef VMS
        f = fopen(name, "rb");
#else
        f = fopen (name, "r", "ctx=stm");
#endif
    }
    return f;
}

FILE*
pm_openw(const char * const name) {
    FILE* f;

    if (strcmp(name, "-") == 0)
        f = stdout;
    else {
#ifndef VMS
        f = fopen(name, "wb");
#else
        f = fopen (name, "w", "mbc=32", "mbf=2");  /* set buffer factors */
#endif
    }
    return f;
}

void
pm_close(FILE * const f) {
Amir Mohammadi's avatar
Amir Mohammadi committed
122
123
124
125
126
127
128
129
130
131
  // fprintf(stderr, "I am closing a file\n");
  fflush( f );
  // if ( ferror( f ) )
    // boost::format m("a file read or write error occurred at some point");
    // throw std::runtime_error(m.str());
  if ( f != stdin )
    fclose( f );
  //   if ( fclose( f ) != 0 )
      // boost::format m("cannot close file.");
      // throw std::runtime_error(m.str());
132
}
133

André Anjos's avatar
André Anjos committed
134
135
136
137
static boost::shared_ptr<std::FILE> make_cfile(const char *filename, const char *flags)
{
  std::FILE* fp;
  if(strcmp(flags, "r") == 0)
138
    fp = pm_openr(filename);
André Anjos's avatar
André Anjos committed
139
  else // write
140
    fp = pm_openw(filename);
André Anjos's avatar
André Anjos committed
141
142
143
144
145
  if(fp == 0) {
    boost::format m("cannot open file `%s'");
    m % filename;
    throw std::runtime_error(m.str());
  }
146
  return boost::shared_ptr<std::FILE>(fp, pm_close);
147
148
149
150
151
152
}

static void pnm_readpaminit(FILE *file, struct pam * const pamP, const int size) {
  int pnm_type=0;
  int x_dim=256, y_dim=256;
  int enable_ascii=1, img_colors=1;
Amir Mohammadi's avatar
Amir Mohammadi committed
153
  int read_err;
154
155
156
157
158
159
160
161

  pamP->file = file;
  pnm_type = get_pnm_type(pamP->file);
  rewind(pamP->file);
  pamP->format = pnm_type;

  /* Read the image file header (the input file has been rewinded). */
  if ((pnm_type == PBM_ASCII) || (pnm_type == PBM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
162
    read_err = read_pbm_header(file, &x_dim, &y_dim, &enable_ascii);
163
164
    pamP->bytes_per_sample = 1;
  } else if ((pnm_type == PGM_ASCII) || (pnm_type == PGM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
165
    read_err = read_pgm_header(file, &x_dim, &y_dim, &img_colors, &enable_ascii);
166
167
168
    if (img_colors >> 8 == 0)       pamP->bytes_per_sample = 1;
    else if (img_colors >> 16 == 0) pamP->bytes_per_sample = 2;
  } else if ((pnm_type == PPM_ASCII) || (pnm_type == PPM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
169
    read_err = read_ppm_header(file, &x_dim, &y_dim, &img_colors, &enable_ascii);
170
171
172
    if (img_colors >> 8 == 0)       pamP->bytes_per_sample = 1;
    else if (img_colors >> 16 == 0) pamP->bytes_per_sample = 2;
  } else {
Amir Mohammadi's avatar
Amir Mohammadi committed
173
174
175
176
177
178
179
    boost::format m("Unknown PNM/PFM image format.");
    throw std::runtime_error(m.str());
  }

  if (read_err != 0) {
    boost::format m("Something went wrong when reading the image file.");
    throw std::runtime_error(m.str());
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  }

  /* Perform operations. */
  if ((pnm_type == PPM_ASCII) || (pnm_type == PPM_BINARY)) {
    pamP->depth = 3;
  } else {
    pamP->depth = 1;
  }
  pamP->width = x_dim;
  pamP->height = y_dim;
  pamP->plainformat = enable_ascii;
  pamP->maxval = img_colors;

}
Amir Mohammadi's avatar
Amir Mohammadi committed
194

195
196
197
198
199
200
201
202
203
204
static int * pnm_allocpam(struct pam * const pamP) {
  int *img_data;
  /* Perform operations. */
  if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
    img_data = (int *) malloc((3 * pamP->width * pamP->height) * sizeof(int));
  } else {
    img_data = (int *) malloc((pamP->width * pamP->height) * sizeof(int));
  }
  return (img_data);
}
Amir Mohammadi's avatar
Amir Mohammadi committed
205

206
static void pnm_readpam(struct pam * const pamP, int *img_data) {
207
  int read_err=1;
208
209
210

  /* Read the image data. */
  if ((pamP->format == PBM_ASCII) || (pamP->format == PBM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
211
    read_err = read_pbm_data(pamP->file, img_data, pamP->width * pamP->height, pamP->plainformat, pamP->width);
212
  } else if ((pamP->format == PGM_ASCII) || (pamP->format == PGM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
213
    read_err = read_pgm_data(pamP->file, img_data, pamP->width * pamP->height, pamP->plainformat, pamP->bytes_per_sample);
214
  } else if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
215
216
217
218
219
220
    read_err = read_ppm_data(pamP->file, img_data, 3 * pamP->width * pamP->height, pamP->plainformat, pamP->bytes_per_sample);
  }

  if (read_err != 0) {
    boost::format m("Something went wrong when reading the image file.");
    throw std::runtime_error(m.str());
221
222
  }
}
Amir Mohammadi's avatar
Amir Mohammadi committed
223

224
static void pnm_writepam(struct pam * const pamP, int *img_data) {
225
  int write_err=1;
Amir Mohammadi's avatar
Amir Mohammadi committed
226

227
228
  /* Write the output image file. */
  if ((pamP->format == PBM_ASCII) || (pamP->format == PBM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
229
    write_err = write_pbm_file(pamP->file, img_data,
230
231
232
      pamP->width, pamP->height, 1, 1, 32, pamP->plainformat
    );
  } else if ((pamP->format == PGM_ASCII) || (pamP->format == PGM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
233
    write_err = write_pgm_file(pamP->file, img_data,
234
235
      pamP->width, pamP->height, 1, 1, pamP->maxval, 16, pamP->plainformat,
      pamP->bytes_per_sample
236
237
    );
  } else if ((pamP->format == PPM_ASCII) || (pamP->format == PPM_BINARY)) {
Amir Mohammadi's avatar
Amir Mohammadi committed
238
    write_err = write_ppm_file(pamP->file, img_data,
239
240
      pamP->width, pamP->height, 1, 1, pamP->maxval, pamP->plainformat,
      pamP->bytes_per_sample
241
242
    );
  }
Amir Mohammadi's avatar
Amir Mohammadi committed
243
244
245
246
247

  if (write_err != 0) {
    boost::format m("Something went wrong when writing the image file.");
    throw std::runtime_error(m.str());
  }
André Anjos's avatar
André Anjos committed
248
249
250
251
252
}

/**
 * LOADING
 */
253
static void im_peek(const std::string& path, bob::io::base::array::typeinfo& info) {
André Anjos's avatar
André Anjos committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

  struct pam in_pam;
  boost::shared_ptr<std::FILE> in_file = make_cfile(path.c_str(), "r");
  pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam));

  if( in_pam.depth != 1 && in_pam.depth != 3)
  {
    boost::format m("unsupported number of planes (%d) when reading file. Image depth must be 1 or 3.");
    m % in_pam.depth;
    throw std::runtime_error(m.str());
  }

  info.nd = (in_pam.depth == 1? 2 : 3);
  if(info.nd == 2)
  {
    info.shape[0] = in_pam.height;
    info.shape[1] = in_pam.width;
  }
  else
  {
    info.shape[0] = 3;
    info.shape[1] = in_pam.height;
    info.shape[2] = in_pam.width;
  }
  info.update_strides();

  // Set depth
281
282
  if (in_pam.bytes_per_sample == 1) info.dtype = bob::io::base::array::t_uint8;
  else if (in_pam.bytes_per_sample == 2) info.dtype = bob::io::base::array::t_uint16;
André Anjos's avatar
André Anjos committed
283
284
285
286
287
288
289
290
  else {
    boost::format m("unsupported image depth (%d bytes per samples) when reading file");
    m % in_pam.bytes_per_sample;
    throw std::runtime_error(m.str());
  }
}

template <typename T> static
291
292
void im_load_gray(struct pam *in_pam, bob::io::base::array::interface& b) {
  const bob::io::base::array::typeinfo& info = b.type();
293
  int c=0;
André Anjos's avatar
André Anjos committed
294
295

  T *element = static_cast<T*>(b.ptr());
296
297
  int *img_data = pnm_allocpam(in_pam);
  pnm_readpam(in_pam, img_data);
André Anjos's avatar
André Anjos committed
298
299
300
301
  for(size_t y=0; y<info.shape[0]; ++y)
  {
    for(size_t x=0; x<info.shape[1]; ++x)
    {
302
      *element = img_data[c];
André Anjos's avatar
André Anjos committed
303
      ++element;
304
      c++;
André Anjos's avatar
André Anjos committed
305
306
    }
  }
307
  free(img_data);
André Anjos's avatar
André Anjos committed
308
309
310
}

template <typename T> static
311
312
void im_load_color(struct pam *in_pam, bob::io::base::array::interface& b) {
  const bob::io::base::array::typeinfo& info = b.type();
313
  int c=0;
André Anjos's avatar
André Anjos committed
314
315
316
317
318
319

  long unsigned int frame_size = info.shape[2] * info.shape[1];
  T *element_r = static_cast<T*>(b.ptr());
  T *element_g = element_r+frame_size;
  T *element_b = element_g+frame_size;

320
321
  int *img_data = pnm_allocpam(in_pam);
  pnm_readpam(in_pam, img_data);
322
  for(size_t y=0; y<info.shape[1]; ++y)
André Anjos's avatar
André Anjos committed
323
  {
324
    for(size_t x=0; x<info.shape[2]; ++x)
325
    {
326
327
328
      element_r[y*info.shape[2] + x] = img_data[c+0];
      element_g[y*info.shape[2] + x] = img_data[c+1];
      element_b[y*info.shape[2] + x] = img_data[c+2];
329
330
      c = c + 3;
    }
André Anjos's avatar
André Anjos committed
331
  }
332
  free(img_data);
André Anjos's avatar
André Anjos committed
333
334
}

335
static void im_load (const std::string& filename, bob::io::base::array::interface& b) {
André Anjos's avatar
André Anjos committed
336
337
338
339
340

  struct pam in_pam;
  boost::shared_ptr<std::FILE> in_file = make_cfile(filename.c_str(), "r");
  pnm_readpaminit(in_file.get(), &in_pam, sizeof(struct pam));

341
  const bob::io::base::array::typeinfo& info = b.type();
André Anjos's avatar
André Anjos committed
342

343
  if (info.dtype == bob::io::base::array::t_uint8) {
André Anjos's avatar
André Anjos committed
344
345
346
347
348
349
350
351
352
    if(info.nd == 2) im_load_gray<uint8_t>(&in_pam, b);
    else if( info.nd == 3) im_load_color<uint8_t>(&in_pam, b);
    else {
      boost::format m("(netpbm) unsupported image type found in file `%s': %s");
      m % filename % info.str();
      throw std::runtime_error(m.str());
    }
  }

353
  else if (info.dtype == bob::io::base::array::t_uint16) {
André Anjos's avatar
André Anjos committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
    if(info.nd == 2) im_load_gray<uint16_t>(&in_pam, b);
    else if( info.nd == 3) im_load_color<uint16_t>(&in_pam, b);
    else {
      boost::format m("(netpbm) unsupported image type found in file `%s': %s");
      m % filename % info.str();
      throw std::runtime_error(m.str());
    }
  }

  else {
    boost::format m("(netpbm) unsupported image type found in file `%s': %s");
    m % filename % info.str();
    throw std::runtime_error(m.str());
  }
}

/**
 * SAVING
 */
template <typename T>
374
375
static void im_save_gray(const bob::io::base::array::interface& b, struct pam *out_pam) {
  const bob::io::base::array::typeinfo& info = b.type();
376
  int c=0;
André Anjos's avatar
André Anjos committed
377
378
379

  const T *element = static_cast<const T*>(b.ptr());

380
381
382
383
384
385
  int *img_data = pnm_allocpam(out_pam);
  for(size_t y=0; y<info.shape[0]; ++y)
  {
    for(size_t x=0; x<info.shape[1]; ++x)
    {
      img_data[c] = *element;
André Anjos's avatar
André Anjos committed
386
      ++element;
387
      c++;
André Anjos's avatar
André Anjos committed
388
389
    }
  }
390
391
  pnm_writepam(out_pam, img_data);
  free(img_data);
André Anjos's avatar
André Anjos committed
392
393
394
395
}


template <typename T>
396
397
static void im_save_color(const bob::io::base::array::interface& b, struct pam *out_pam) {
  const bob::io::base::array::typeinfo& info = b.type();
398
  int c=0;
André Anjos's avatar
André Anjos committed
399
400
401
402
403
404

  long unsigned int frame_size = info.shape[2] * info.shape[1];
  const T *element_r = static_cast<const T*>(b.ptr());
  const T *element_g = element_r + frame_size;
  const T *element_b = element_g + frame_size;

405
  int *img_data = pnm_allocpam(out_pam);
406
  for(size_t y=0; y<info.shape[1]; ++y)
407
  {
408
    for(size_t x=0; x<info.shape[2]; ++x)
409
    {
410
411
412
      img_data[c+0] = element_r[y*info.shape[2] + x];
      img_data[c+1] = element_g[y*info.shape[2] + x];
      img_data[c+2] = element_b[y*info.shape[2] + x];
413
414
      c = c + 3;
    }
André Anjos's avatar
André Anjos committed
415
  }
416
417
  pnm_writepam(out_pam, img_data);
  free(img_data);
André Anjos's avatar
André Anjos committed
418
419
}

420
static void im_save (const std::string& filename, const bob::io::base::array::interface& array) {
André Anjos's avatar
André Anjos committed
421

422
  const bob::io::base::array::typeinfo& info = array.type();
André Anjos's avatar
André Anjos committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

  struct pam out_pam;
  boost::shared_ptr<std::FILE> out_file = make_cfile(filename.c_str(), "w");

  std::string ext = boost::filesystem::path(filename).extension().c_str();
  boost::algorithm::to_lower(ext);

  // Sets the parameters of the pam structure according to the bca::interface properties
  out_pam.size = sizeof(out_pam);
  out_pam.len = out_pam.size;
  out_pam.file = out_file.get();
  out_pam.plainformat = 0; // writes in binary
  out_pam.height = (info.nd == 2 ? info.shape[0] : info.shape[1]);
  out_pam.width = (info.nd == 2 ? info.shape[1] : info.shape[2]);
  out_pam.depth = (info.nd == 2 ? 1 : 3);
438
  out_pam.maxval = (info.dtype == bob::io::base::array::t_uint8 ? 255 : 65535);
439
  out_pam.bytes_per_sample = (info.dtype == bob::io::base::array::t_uint8 ? 1 : 2);
André Anjos's avatar
André Anjos committed
440
441
442
  if( ext.compare(".pbm") == 0)
  {
    out_pam.maxval = 1;
443
    out_pam.format = PBM_BINARY;
André Anjos's avatar
André Anjos committed
444
445
446
  }
  else if( ext.compare(".pgm") == 0)
  {
447
    out_pam.format = PGM_BINARY;
André Anjos's avatar
André Anjos committed
448
449
450
  }
  else
  {
451
    out_pam.format = PPM_BINARY;
André Anjos's avatar
André Anjos committed
452
453
454
455
456
457
458
  }

  if(out_pam.depth == 3 && ext.compare(".ppm")) {
    throw std::runtime_error("cannot save a color image into a file of this type.");
  }

  // Writes content
459
  if(info.dtype == bob::io::base::array::t_uint8) {
André Anjos's avatar
André Anjos committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473

    if(info.nd == 2) im_save_gray<uint8_t>(array, &out_pam);
    else if(info.nd == 3) {
      if(info.shape[0] != 3) throw std::runtime_error("color image does not have 3 planes on 1st. dimension");
      im_save_color<uint8_t>(array, &out_pam);
    }
    else {
      boost::format m("(netpbm) cannot write object of type `%s' to file `%s'");
      m % info.str() % filename;
      throw std::runtime_error(m.str());
    }

  }

474
  else if(info.dtype == bob::io::base::array::t_uint16) {
André Anjos's avatar
André Anjos committed
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496

    if(info.nd == 2) im_save_gray<uint16_t>(array, &out_pam);
    else if(info.nd == 3) {
      if(info.shape[0] != 3) throw std::runtime_error("color image does not have 3 planes on 1st. dimension");
      im_save_color<uint16_t>(array, &out_pam);
    }
    else {
      boost::format m("(netpbm) cannot write object of type `%s' to file `%s'");
      m % info.str() % filename;
      throw std::runtime_error(m.str());
    }

  }

  else {
    boost::format m("(netpbm) cannot write object of type `%s' to file `%s'");
    m % info.str() % filename;
    throw std::runtime_error(m.str());
  }
}


Manuel Günther's avatar
Manuel Günther committed
497
498
499
/**
 * NetPBM class
*/
André Anjos's avatar
André Anjos committed
500

Manuel Günther's avatar
Manuel Günther committed
501
502
503
504
505
506
507
508
509
510
bob::io::image::NetPBMFile::NetPBMFile(const char* path, char mode)
: m_filename(path),
  m_newfile(true)
{
  //checks if file exists
  if (mode == 'r' && !boost::filesystem::exists(path)) {
    boost::format m("file '%s' is not readable");
    m % path;
    throw std::runtime_error(m.str());
  }
André Anjos's avatar
André Anjos committed
511

Manuel Günther's avatar
Manuel Günther committed
512
513
514
515
516
517
518
519
520
  if (mode == 'r' || (mode == 'a' && boost::filesystem::exists(path))) {
    im_peek(path, m_type);
    m_length = 1;
    m_newfile = false;
  } else {
    m_length = 0;
    m_newfile = true;
  }
}
André Anjos's avatar
André Anjos committed
521

Manuel Günther's avatar
Manuel Günther committed
522
523
524
void bob::io::image::NetPBMFile::read(bob::io::base::array::interface& buffer, size_t index) {
  if (m_newfile)
    throw std::runtime_error("uninitialized image file cannot be read");
André Anjos's avatar
André Anjos committed
525

Manuel Günther's avatar
Manuel Günther committed
526
  if (!buffer.type().is_compatible(m_type)) buffer.set(m_type);
André Anjos's avatar
André Anjos committed
527

Manuel Günther's avatar
Manuel Günther committed
528
529
  if (index != 0)
    throw std::runtime_error("cannot read image with index > 0 -- there is only one image in an image file");
André Anjos's avatar
André Anjos committed
530

Manuel Günther's avatar
Manuel Günther committed
531
532
533
  if(!buffer.type().is_compatible(m_type)) buffer.set(m_type);
  im_load(m_filename, buffer);
}
André Anjos's avatar
André Anjos committed
534

Manuel Günther's avatar
Manuel Günther committed
535
536
537
538
539
540
541
542
size_t bob::io::image::NetPBMFile::append(const bob::io::base::array::interface& buffer) {
  if (m_newfile) {
    im_save(m_filename, buffer);
    m_type = buffer.type();
    m_newfile = false;
    m_length = 1;
    return 0;
  }
André Anjos's avatar
André Anjos committed
543

Manuel Günther's avatar
Manuel Günther committed
544
545
  throw std::runtime_error("image files only accept a single array");
}
André Anjos's avatar
André Anjos committed
546

Manuel Günther's avatar
Manuel Günther committed
547
548
549
550
551
552
void bob::io::image::NetPBMFile::write(const bob::io::base::array::interface& buffer) {
  //overwriting position 0 should always work
  if (m_newfile) {
    append(buffer);
    return;
  }
André Anjos's avatar
André Anjos committed
553

Manuel Günther's avatar
Manuel Günther committed
554
555
  throw std::runtime_error("image files only accept a single array");
}
André Anjos's avatar
André Anjos committed
556

Manuel Günther's avatar
Manuel Günther committed
557
std::string bob::io::image::NetPBMFile::s_codecname = "bob.image_netpbm";
André Anjos's avatar
André Anjos committed
558
559


560
boost::shared_ptr<bob::io::base::File> make_netpbm_file (const char* path, char mode) {
Manuel Günther's avatar
Manuel Günther committed
561
  return boost::make_shared<bob::io::image::NetPBMFile>(path, mode);
André Anjos's avatar
André Anjos committed
562
}