Fawkes API  Fawkes Development Version
pnm.cpp
1 
2 /***************************************************************************
3  * pnm.cpp - Implementation of a PNM writer
4  *
5  * Generated: Mon Feb 06 19:18:03 2006
6  * Copyright 2005-2007 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exception.h>
25 #include <core/exceptions/system.h>
26 #include <fvutils/writers/pnm.h>
27 #include <fvutils/color/conversions.h>
28 
29 #include <cstdio>
30 #include <cstdlib>
31 
32 using namespace fawkes;
33 
34 namespace firevision {
35 #if 0 /* just to make Emacs auto-indent happy */
36 }
37 #endif
38 
39 /** @class PNMWriter <fvutils/writers/pnm.h>
40  * PNM file writer.
41  */
42 
43 /** Constructor.
44  * @param format PNM subformat
45  */
46 PNMWriter::PNMWriter(PNMFormat format)
47  : Writer("pnm")
48 {
49  this->format = format;
50 
51  buffer_size = calc_buffer_size();
52  buffer = (unsigned char *)malloc(buffer_size);
53  buffer_start = buffer;
54 }
55 
56 /** Constructor.
57  * @param format PNM subformat
58  * @param filename filename
59  * @param width image width
60  * @param height image height
61  */
62 PNMWriter::PNMWriter(PNMFormat format, const char *filename, unsigned int width, unsigned int height)
63  : Writer("pnm")
64 {
65  set_filename(filename);
66 
67  this->format = format;
68  this->width = width;
69  this->height = height;
70 
71  buffer_size = calc_buffer_size();
72  buffer = (unsigned char *)malloc(buffer_size);
73  buffer_start = buffer;
74 }
75 
76 
77 void
78 PNMWriter::set_buffer(colorspace_t cspace, unsigned char *yuv422_planar_buf)
79 {
80  if (cspace != YUV422_PLANAR) {
81  throw Exception("Unsupported colorspace, PNM can only write YUV422_PLANAR images");
82  }
83 
84  buffer = buffer_start;
85  memset(buffer, 0, buffer_size);
86 
87  buffer += write_header();
88 
89  unsigned char *yp, *up, *vp;
90  unsigned char y1, y2, u, v;
91 
92  yp = yuv422_planar_buf;
93  up = YUV422_PLANAR_U_PLANE(yuv422_planar_buf, width, height);
94  vp = YUV422_PLANAR_V_PLANE(yuv422_planar_buf, width, height);
95 
96 
97  if ( (format == PNM_PBM) ||
98  (format == PNM_PBM_ASCII) ) {
99 
100  unsigned char byte = 0;
101  unsigned int num_bits = 0;
102 
103  for (unsigned int i = 0; i < height; ++i) {
104  byte = 0;
105  num_bits = 0;
106  for (unsigned int j = 0; j < width; ++j) {
107  y1 = *yp++;
108  if (y1 > 127) {
109  y2 = 1;
110  } else {
111  y2 = 0;
112  }
113  if ( format == PNM_PBM ) {
114  byte |= (y2 << (7-num_bits++));
115  if (num_bits == 8) {
116  *buffer++ = byte;
117  byte = 0;
118  num_bits = 0;
119  }
120  } else {
121  // PNM_PBM_ASCII
122  sprintf((char *)buffer, "%c ", y2);
123  buffer += 2;
124  }
125  }
126  if ((format == PNM_PBM) && (num_bits != 0)) {
127  *buffer++ = byte;
128  }
129  }
130  } else if ( (format == PNM_PGM) ||
131  (format == PNM_PGM_ASCII) ) {
132 
133  for (unsigned int i = 0; i < height; ++i) {
134  for (unsigned int j = 0; j < width; ++j) {
135  y1 = *yp++;
136  if ( format == PNM_PGM ) {
137  *buffer++ = y1;
138  } else {
139  // PNM_PGM_ASCII
140  sprintf((char *)buffer, "%3c ", y1);
141  buffer += 4;
142  }
143  }
144  }
145 
146  } else if ( format == PNM_PPM ) {
147 
148  convert(YUV422_PLANAR, RGB, yuv422_planar_buf, buffer, width, height);
149 
150  } else if (format == PNM_PPM_ASCII) {
151 
152  unsigned char r, g, b;
153 
154  for (unsigned int i = 0; i < height; ++i) {
155  for (unsigned int j = 0; j < (width / 2); ++j) {
156  y1 = *yp++;
157  y2 = *yp++;
158  u = *up++;
159  v = *vp++;
160 
161  pixel_yuv_to_rgb(y1, u, v, &r, &g, &b);
162  sprintf((char *)buffer, "%3c %3c %3c ", r, g, b);
163  buffer += 13;
164 
165  pixel_yuv_to_rgb(y2, u, v, &r, &g, &b);
166  sprintf((char *)buffer, "%3c %3c %3c ", r, g, b);
167  buffer += 13;
168  }
169  }
170  }
171 
172 }
173 
174 
175 const char *
176 PNMWriter::format2string(PNMFormat format)
177 {
178  switch ( format ) {
179  case PNM_PBM: return "P4";
180  case PNM_PBM_ASCII: return "P1";
181  case PNM_PGM: return "P5";
182  case PNM_PGM_ASCII: return "P2";
183  case PNM_PPM: return "P6";
184  case PNM_PPM_ASCII: return "P3";
185 
186  default:
187  throw Exception("Unknown PNMFormat");
188  }
189 }
190 
191 unsigned int
192 PNMWriter::write_header(bool simulate)
193 {
194  unsigned int rv = 25;
195 
196  if (! simulate) {
197  switch ( format ) {
198  case PNM_PBM:
199  case PNM_PBM_ASCII:
200  sprintf((char *)buffer, "%s %10u %10u\n", format2string(format), width, height);
201  break;
202 
203  case PNM_PGM:
204  case PNM_PGM_ASCII:
205  case PNM_PPM:
206  case PNM_PPM_ASCII:
207  sprintf((char *)buffer, "%s %10u %10u 255\n", format2string(format), width, height);
208  break;
209  default: break;
210  }
211  }
212 
213  switch (format) {
214  case PNM_PGM:
215  case PNM_PGM_ASCII:
216  case PNM_PPM:
217  case PNM_PPM_ASCII:
218  rv += 4;
219  break;
220  default: break;
221  }
222 
223  return rv;
224 }
225 
226 
227 void
229 {
230  FILE *fp = fopen(filename, "wb");
231  if (!fp) {
232  throw Exception("Could not open file for writing");
233  }
234 
235  if (fwrite(buffer_start, buffer_size, 1, fp) != 1) {
236  throw FileWriteException(filename, "Failed to write data");
237  }
238  fclose(fp);
239 
240 }
241 
242 
243 unsigned int
244 PNMWriter::calc_buffer_size()
245 {
246  unsigned int rv = write_header(true);
247 
248  unsigned int num_row_bytes = 0;
249 
250  switch ( format ) {
251  case PNM_PBM:
252  // full bytes
253  num_row_bytes = width / 8;
254  if ((width % 8) != 0) {
255  // possibly the last non-full byte
256  num_row_bytes += 1;
257  }
258  break;
259 
260  case PNM_PBM_ASCII:
261  // width numbers + width - 1 white spaces + \n
262  num_row_bytes = 2 * width;
263  break;
264 
265  case PNM_PGM:
266  num_row_bytes = width;
267  break;
268 
269  case PNM_PGM_ASCII:
270  num_row_bytes = width * 4;
271  break;
272 
273  case PNM_PPM:
274  num_row_bytes = 3 * width;
275  break;
276 
277  case PNM_PPM_ASCII:
278  // why 13?
279  // 3 + 1 for each number (0 to 255) per component and following whitespace
280  // * 3 three components
281  // = 12
282  // + 1 for an extra white space after each pixel
283  // = 13
284  num_row_bytes = width * 13;
285  break;
286 
287  default: break;
288  }
289 
290  rv += num_row_bytes * height;
291 
292  return rv;
293 }
294 
295 } // end namespace firevision
colorspace_t cspace
The colorspace of the image.
Definition: writer.h:55
Fawkes library namespace.
Interface to write images.
Definition: writer.h:34
virtual void write()
Write to file.
Definition: pnm.cpp:228
Base class for exceptions in Fawkes.
Definition: exception.h:36
Could not write to file.
Definition: system.h:68
PNMWriter(PNMFormat format)
Constructor.
Definition: pnm.cpp:46
virtual void set_filename(const char *filename)
Set filename.
Definition: writer.cpp:106
virtual void set_buffer(colorspace_t cspace, unsigned char *buffer)
Set image buffer.
Definition: pnm.cpp:78
char * filename
The complete filename.
Definition: writer.h:48