pnm.cpp

00001
00002 /***************************************************************************
00003  *  pnm.cpp - Implementation of a PNM writer
00004  *
00005  *  Generated: Mon Feb 06 19:18:03 2006
00006  *  Copyright  2005-2007  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <core/exception.h>
00025 #include <fvutils/writers/pnm.h>
00026 #include <fvutils/color/conversions.h>
00027
00028 #include <cstdio>
00029 #include <cstdlib>
00030
00031 using namespace fawkes;
00032 
00033 /** @class PNMWriter <fvutils/writers/pnm.h>
00034  * PNM file writer.
00035  */
00036 
00037 /** Constructor.
00038  * @param format PNM subformat
00039  */
00040 PNMWriter::PNMWriter(PNMFormat format)
00041   : Writer("pnm")
00042 {
00043   this->format = format;
00044
00045   buffer_size = calc_buffer_size();
00046   buffer = (unsigned char *)malloc(buffer_size);
00047   buffer_start = buffer;
00048 }
00049 
00050 /** Constructor.
00051  * @param format PNM subformat
00052  * @param filename filename
00053  * @param width image width
00054  * @param height image height
00055  */
00056 PNMWriter::PNMWriter(PNMFormat format, const char *filename, unsigned int width, unsigned int height)
00057   : Writer("pnm")
00058 {
00059   set_filename(filename);
00060
00061   this->format = format;
00062   this->width = width;
00063   this->height = height;
00064
00065   buffer_size = calc_buffer_size();
00066   buffer = (unsigned char *)malloc(buffer_size);
00067   buffer_start = buffer;
00068 }
00069
00070
00071 void
00072 PNMWriter::set_buffer(colorspace_t cspace, unsigned char *yuv422_planar_buf)
00073 {
00074   if (cspace != YUV422_PLANAR) {
00075     throw Exception("Unsupported colorspace, PNM can only write YUV422_PLANAR images");
00076   }
00077
00078   buffer = buffer_start;
00079   memset(buffer, 0, buffer_size);
00080
00081   buffer += write_header();
00082
00083   unsigned char *yp, *up, *vp;
00084   unsigned char y1, y2, u, v;
00085
00086   yp = yuv422_planar_buf;
00087   up = YUV422_PLANAR_U_PLANE(yuv422_planar_buf, width, height);
00088   vp = YUV422_PLANAR_V_PLANE(yuv422_planar_buf, width, height);
00089
00090
00091   if ( (format == PNM_PBM) ||
00092        (format == PNM_PBM_ASCII) ) {
00093
00094     unsigned char byte     = 0;
00095     unsigned int  num_bits = 0;
00096
00097     for (unsigned int i = 0; i < height; ++i) {
00098       byte = 0;
00099       num_bits = 0;
00100       for (unsigned int j = 0; j < width; ++j) {
00101         y1 = *yp++;
00102         if (y1 > 127) {
00103           y2 = 1;
00104         } else {
00105           y2 = 0;
00106         }
00107         if ( format == PNM_PBM ) {
00108           byte |= (y2 << (7-num_bits++));
00109           if (num_bits == 8) {
00110             *buffer++ = byte;
00111             byte = 0;
00112             num_bits = 0;
00113           }
00114         } else {
00115           // PNM_PBM_ASCII
00116           sprintf((char *)buffer, "%c ", y2);
00117           buffer += 2;
00118         }
00119       }
00120       if ((format == PNM_PBM) && (num_bits != 0)) {
00121         *buffer++ = byte;
00122       }
00123     }
00124   } else if ( (format == PNM_PGM) ||
00125               (format == PNM_PGM_ASCII) ) {
00126
00127     for (unsigned int i = 0; i < height; ++i) {
00128       for (unsigned int j = 0; j < width; ++j) {
00129         y1 = *yp++;
00130         if ( format == PNM_PGM ) {
00131           *buffer++ = y1;
00132         } else {
00133           // PNM_PGM_ASCII
00134           sprintf((char *)buffer, "%3c ", y1);
00135           buffer += 4;
00136         }
00137       }
00138     }
00139
00140   } else if ( format == PNM_PPM ) {
00141
00142     convert(YUV422_PLANAR, RGB, yuv422_planar_buf, buffer, width, height);
00143
00144   } else if (format == PNM_PPM_ASCII) {
00145
00146     unsigned char r, g, b;
00147
00148     for (unsigned int i = 0; i < height; ++i) {
00149       for (unsigned int j = 0; j < (width / 2); ++j) {
00150         y1 = *yp++;
00151         y2 = *yp++;
00152         u  = *up++;
00153         v  = *vp++;
00154
00155         pixel_yuv_to_rgb(y1, u, v, &r, &g, &b);
00156         sprintf((char *)buffer, "%3c %3c %3c  ", r, g, b);
00157         buffer += 13;
00158
00159         pixel_yuv_to_rgb(y2, u, v, &r, &g, &b);
00160         sprintf((char *)buffer, "%3c %3c %3c  ", r, g, b);
00161         buffer += 13;
00162       }
00163     }
00164   }
00165
00166 }
00167
00168
00169 const char *
00170 PNMWriter::format2string(PNMFormat format)
00171 {
00172   switch ( format ) {
00173   case PNM_PBM:        return "P4";
00174   case PNM_PBM_ASCII:  return "P1";
00175   case PNM_PGM:        return "P5";
00176   case PNM_PGM_ASCII:  return "P2";
00177   case PNM_PPM:        return "P6";
00178   case PNM_PPM_ASCII:  return "P3";
00179
00180   default:
00181     throw Exception("Unknown PNMFormat");
00182   }
00183 }
00184
00185 unsigned int
00186 PNMWriter::write_header(bool simulate)
00187 {
00188   unsigned int rv = 25;
00189
00190   if (! simulate) {
00191     switch ( format ) {
00192     case PNM_PBM:
00193     case PNM_PBM_ASCII:
00194       sprintf((char *)buffer, "%s %10u %10u\n", format2string(format), width, height);
00195       break;
00196
00197     case PNM_PGM:
00198     case PNM_PGM_ASCII:
00199     case PNM_PPM:
00200     case PNM_PPM_ASCII:
00201       sprintf((char *)buffer, "%s %10u %10u 255\n", format2string(format), width, height);
00202       break;
00203     default: break;
00204     }
00205   }
00206
00207   switch (format) {
00208   case PNM_PGM:
00209   case PNM_PGM_ASCII:
00210   case PNM_PPM:
00211   case PNM_PPM_ASCII:
00212     rv += 4;
00213     break;
00214   default: break;
00215   }
00216
00217   return rv;
00218 }
00219
00220
00221 void
00222 PNMWriter::write()
00223 {
00224   FILE *fp = fopen(filename, "wb");
00225   if (!fp) {
00226     throw Exception("Could not open file for writing");
00227   }
00228
00229   fwrite(buffer_start, buffer_size, 1, fp);
00230   fclose(fp);
00231
00232 }
00233
00234
00235 unsigned int
00236 PNMWriter::calc_buffer_size()
00237 {
00238   unsigned int rv = write_header(true);
00239
00240   unsigned int num_row_bytes = 0;
00241
00242   switch ( format ) {
00243   case PNM_PBM:
00244     // full bytes
00245     num_row_bytes = width / 8;
00246     if ((width % 8) != 0) {
00247       // possibly the last non-full byte
00248       num_row_bytes += 1;
00249     }
00250     break;
00251
00252   case PNM_PBM_ASCII:
00253     // width numbers + width - 1 white spaces + \n
00254     num_row_bytes = 2 * width;
00255     break;
00256
00257   case PNM_PGM:
00258     num_row_bytes = width;
00259     break;
00260
00261   case PNM_PGM_ASCII:
00262     num_row_bytes = width * 4;
00263     break;
00264
00265   case PNM_PPM:
00266     num_row_bytes = 3 * width;
00267     break;
00268
00269   case PNM_PPM_ASCII:
00270     // why 13?
00271     // 3 + 1  for each number (0 to 255) per component and following whitespace
00272     // * 3  three components
00273     // = 12
00274     // + 1 for an extra white space after each pixel
00275     // = 13
00276     num_row_bytes = width * 13;
00277     break;
00278
00279   default: break;
00280   }
00281
00282   rv += num_row_bytes * height;
00283
00284   return rv;
00285 }