00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00034
00035
00036
00037
00038
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
00051
00052
00053
00054
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
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
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
00245 num_row_bytes = width / 8;
00246 if ((width % 8) != 0) {
00247
00248 num_row_bytes += 1;
00249 }
00250 break;
00251
00252 case PNM_PBM_ASCII:
00253
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
00271
00272
00273
00274
00275
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 }