Fawkes API
Fawkes Development Version
|
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 <core/exceptions/system.h> 00026 #include <fvutils/writers/pnm.h> 00027 #include <fvutils/color/conversions.h> 00028 00029 #include <cstdio> 00030 #include <cstdlib> 00031 00032 using namespace fawkes; 00033 00034 namespace firevision { 00035 #if 0 /* just to make Emacs auto-indent happy */ 00036 } 00037 #endif 00038 00039 /** @class PNMWriter <fvutils/writers/pnm.h> 00040 * PNM file writer. 00041 */ 00042 00043 /** Constructor. 00044 * @param format PNM subformat 00045 */ 00046 PNMWriter::PNMWriter(PNMFormat format) 00047 : Writer("pnm") 00048 { 00049 this->format = format; 00050 00051 buffer_size = calc_buffer_size(); 00052 buffer = (unsigned char *)malloc(buffer_size); 00053 buffer_start = buffer; 00054 } 00055 00056 /** Constructor. 00057 * @param format PNM subformat 00058 * @param filename filename 00059 * @param width image width 00060 * @param height image height 00061 */ 00062 PNMWriter::PNMWriter(PNMFormat format, const char *filename, unsigned int width, unsigned int height) 00063 : Writer("pnm") 00064 { 00065 set_filename(filename); 00066 00067 this->format = format; 00068 this->width = width; 00069 this->height = height; 00070 00071 buffer_size = calc_buffer_size(); 00072 buffer = (unsigned char *)malloc(buffer_size); 00073 buffer_start = buffer; 00074 } 00075 00076 00077 void 00078 PNMWriter::set_buffer(colorspace_t cspace, unsigned char *yuv422_planar_buf) 00079 { 00080 if (cspace != YUV422_PLANAR) { 00081 throw Exception("Unsupported colorspace, PNM can only write YUV422_PLANAR images"); 00082 } 00083 00084 buffer = buffer_start; 00085 memset(buffer, 0, buffer_size); 00086 00087 buffer += write_header(); 00088 00089 unsigned char *yp, *up, *vp; 00090 unsigned char y1, y2, u, v; 00091 00092 yp = yuv422_planar_buf; 00093 up = YUV422_PLANAR_U_PLANE(yuv422_planar_buf, width, height); 00094 vp = YUV422_PLANAR_V_PLANE(yuv422_planar_buf, width, height); 00095 00096 00097 if ( (format == PNM_PBM) || 00098 (format == PNM_PBM_ASCII) ) { 00099 00100 unsigned char byte = 0; 00101 unsigned int num_bits = 0; 00102 00103 for (unsigned int i = 0; i < height; ++i) { 00104 byte = 0; 00105 num_bits = 0; 00106 for (unsigned int j = 0; j < width; ++j) { 00107 y1 = *yp++; 00108 if (y1 > 127) { 00109 y2 = 1; 00110 } else { 00111 y2 = 0; 00112 } 00113 if ( format == PNM_PBM ) { 00114 byte |= (y2 << (7-num_bits++)); 00115 if (num_bits == 8) { 00116 *buffer++ = byte; 00117 byte = 0; 00118 num_bits = 0; 00119 } 00120 } else { 00121 // PNM_PBM_ASCII 00122 sprintf((char *)buffer, "%c ", y2); 00123 buffer += 2; 00124 } 00125 } 00126 if ((format == PNM_PBM) && (num_bits != 0)) { 00127 *buffer++ = byte; 00128 } 00129 } 00130 } else if ( (format == PNM_PGM) || 00131 (format == PNM_PGM_ASCII) ) { 00132 00133 for (unsigned int i = 0; i < height; ++i) { 00134 for (unsigned int j = 0; j < width; ++j) { 00135 y1 = *yp++; 00136 if ( format == PNM_PGM ) { 00137 *buffer++ = y1; 00138 } else { 00139 // PNM_PGM_ASCII 00140 sprintf((char *)buffer, "%3c ", y1); 00141 buffer += 4; 00142 } 00143 } 00144 } 00145 00146 } else if ( format == PNM_PPM ) { 00147 00148 convert(YUV422_PLANAR, RGB, yuv422_planar_buf, buffer, width, height); 00149 00150 } else if (format == PNM_PPM_ASCII) { 00151 00152 unsigned char r, g, b; 00153 00154 for (unsigned int i = 0; i < height; ++i) { 00155 for (unsigned int j = 0; j < (width / 2); ++j) { 00156 y1 = *yp++; 00157 y2 = *yp++; 00158 u = *up++; 00159 v = *vp++; 00160 00161 pixel_yuv_to_rgb(y1, u, v, &r, &g, &b); 00162 sprintf((char *)buffer, "%3c %3c %3c ", r, g, b); 00163 buffer += 13; 00164 00165 pixel_yuv_to_rgb(y2, u, v, &r, &g, &b); 00166 sprintf((char *)buffer, "%3c %3c %3c ", r, g, b); 00167 buffer += 13; 00168 } 00169 } 00170 } 00171 00172 } 00173 00174 00175 const char * 00176 PNMWriter::format2string(PNMFormat format) 00177 { 00178 switch ( format ) { 00179 case PNM_PBM: return "P4"; 00180 case PNM_PBM_ASCII: return "P1"; 00181 case PNM_PGM: return "P5"; 00182 case PNM_PGM_ASCII: return "P2"; 00183 case PNM_PPM: return "P6"; 00184 case PNM_PPM_ASCII: return "P3"; 00185 00186 default: 00187 throw Exception("Unknown PNMFormat"); 00188 } 00189 } 00190 00191 unsigned int 00192 PNMWriter::write_header(bool simulate) 00193 { 00194 unsigned int rv = 25; 00195 00196 if (! simulate) { 00197 switch ( format ) { 00198 case PNM_PBM: 00199 case PNM_PBM_ASCII: 00200 sprintf((char *)buffer, "%s %10u %10u\n", format2string(format), width, height); 00201 break; 00202 00203 case PNM_PGM: 00204 case PNM_PGM_ASCII: 00205 case PNM_PPM: 00206 case PNM_PPM_ASCII: 00207 sprintf((char *)buffer, "%s %10u %10u 255\n", format2string(format), width, height); 00208 break; 00209 default: break; 00210 } 00211 } 00212 00213 switch (format) { 00214 case PNM_PGM: 00215 case PNM_PGM_ASCII: 00216 case PNM_PPM: 00217 case PNM_PPM_ASCII: 00218 rv += 4; 00219 break; 00220 default: break; 00221 } 00222 00223 return rv; 00224 } 00225 00226 00227 void 00228 PNMWriter::write() 00229 { 00230 FILE *fp = fopen(filename, "wb"); 00231 if (!fp) { 00232 throw Exception("Could not open file for writing"); 00233 } 00234 00235 if (fwrite(buffer_start, buffer_size, 1, fp) != 1) { 00236 throw FileWriteException(filename, "Failed to write data"); 00237 } 00238 fclose(fp); 00239 00240 } 00241 00242 00243 unsigned int 00244 PNMWriter::calc_buffer_size() 00245 { 00246 unsigned int rv = write_header(true); 00247 00248 unsigned int num_row_bytes = 0; 00249 00250 switch ( format ) { 00251 case PNM_PBM: 00252 // full bytes 00253 num_row_bytes = width / 8; 00254 if ((width % 8) != 0) { 00255 // possibly the last non-full byte 00256 num_row_bytes += 1; 00257 } 00258 break; 00259 00260 case PNM_PBM_ASCII: 00261 // width numbers + width - 1 white spaces + \n 00262 num_row_bytes = 2 * width; 00263 break; 00264 00265 case PNM_PGM: 00266 num_row_bytes = width; 00267 break; 00268 00269 case PNM_PGM_ASCII: 00270 num_row_bytes = width * 4; 00271 break; 00272 00273 case PNM_PPM: 00274 num_row_bytes = 3 * width; 00275 break; 00276 00277 case PNM_PPM_ASCII: 00278 // why 13? 00279 // 3 + 1 for each number (0 to 255) per component and following whitespace 00280 // * 3 three components 00281 // = 12 00282 // + 1 for an extra white space after each pixel 00283 // = 13 00284 num_row_bytes = width * 13; 00285 break; 00286 00287 default: break; 00288 } 00289 00290 rv += num_row_bytes * height; 00291 00292 return rv; 00293 } 00294 00295 } // end namespace firevision