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/color/conversions.h>
27 #include <fvutils/color/yuv.h>
28 #include <fvutils/color/yuvrgb.h>
29 #include <fvutils/writers/pnm.h>
30 
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 
35 using namespace fawkes;
36 
37 namespace firevision {
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) : Writer("pnm")
47 {
48  this->format = format;
49 
50  buffer_size = calc_buffer_size();
51  buffer = (unsigned char *)malloc(buffer_size);
52  buffer_start = buffer;
53 }
54 
55 /** Constructor.
56  * @param format PNM subformat
57  * @param filename filename
58  * @param width image width
59  * @param height image height
60  */
61 PNMWriter::PNMWriter(PNMFormat format,
62  const char * filename,
63  unsigned int width,
64  unsigned int height)
65 : Writer("pnm")
66 {
68 
69  this->format = format;
70  this->width = width;
71  this->height = height;
72 
73  buffer_size = calc_buffer_size();
74  buffer = (unsigned char *)malloc(buffer_size);
75  buffer_start = buffer;
76 }
77 
78 void
79 PNMWriter::set_buffer(colorspace_t cspace, unsigned char *yuv422_planar_buf)
80 {
81  if (cspace != YUV422_PLANAR) {
82  throw Exception("Unsupported colorspace, PNM can only write YUV422_PLANAR images");
83  }
84 
85  buffer = buffer_start;
86  memset(buffer, 0, buffer_size);
87 
88  buffer += write_header();
89 
90  unsigned char *yp, *up, *vp;
91  unsigned char y1, y2, u, v;
92 
93  yp = yuv422_planar_buf;
94  up = YUV422_PLANAR_U_PLANE(yuv422_planar_buf, width, height);
95  vp = YUV422_PLANAR_V_PLANE(yuv422_planar_buf, width, height);
96 
97  if ((format == PNM_PBM) || (format == PNM_PBM_ASCII)) {
98  unsigned char byte = 0;
99  unsigned int num_bits = 0;
100 
101  for (unsigned int i = 0; i < height; ++i) {
102  byte = 0;
103  num_bits = 0;
104  for (unsigned int j = 0; j < width; ++j) {
105  y1 = *yp++;
106  if (y1 > 127) {
107  y2 = 1;
108  } else {
109  y2 = 0;
110  }
111  if (format == PNM_PBM) {
112  byte |= (y2 << (7 - num_bits++));
113  if (num_bits == 8) {
114  *buffer++ = byte;
115  byte = 0;
116  num_bits = 0;
117  }
118  } else {
119  // PNM_PBM_ASCII
120  sprintf((char *)buffer, "%c ", y2);
121  buffer += 2;
122  }
123  }
124  if ((format == PNM_PBM) && (num_bits != 0)) {
125  *buffer++ = byte;
126  }
127  }
128  } else if ((format == PNM_PGM) || (format == PNM_PGM_ASCII)) {
129  for (unsigned int i = 0; i < height; ++i) {
130  for (unsigned int j = 0; j < width; ++j) {
131  y1 = *yp++;
132  if (format == PNM_PGM) {
133  *buffer++ = y1;
134  } else {
135  // PNM_PGM_ASCII
136  sprintf((char *)buffer, "%3c ", y1);
137  buffer += 4;
138  }
139  }
140  }
141 
142  } else if (format == PNM_PPM) {
143  convert(YUV422_PLANAR, RGB, yuv422_planar_buf, buffer, width, height);
144 
145  } else if (format == PNM_PPM_ASCII) {
146  unsigned char r, g, b;
147 
148  for (unsigned int i = 0; i < height; ++i) {
149  for (unsigned int j = 0; j < (width / 2); ++j) {
150  y1 = *yp++;
151  y2 = *yp++;
152  u = *up++;
153  v = *vp++;
154 
155  pixel_yuv_to_rgb(y1, u, v, &r, &g, &b);
156  sprintf((char *)buffer, "%3c %3c %3c ", r, g, b);
157  buffer += 13;
158 
159  pixel_yuv_to_rgb(y2, u, v, &r, &g, &b);
160  sprintf((char *)buffer, "%3c %3c %3c ", r, g, b);
161  buffer += 13;
162  }
163  }
164  }
165 }
166 
167 const char *
168 PNMWriter::format2string(PNMFormat format)
169 {
170  switch (format) {
171  case PNM_PBM: return "P4";
172  case PNM_PBM_ASCII: return "P1";
173  case PNM_PGM: return "P5";
174  case PNM_PGM_ASCII: return "P2";
175  case PNM_PPM: return "P6";
176  case PNM_PPM_ASCII: return "P3";
177 
178  default: throw Exception("Unknown PNMFormat");
179  }
180 }
181 
182 unsigned int
183 PNMWriter::write_header(bool simulate)
184 {
185  unsigned int rv = 25;
186 
187  if (!simulate) {
188  switch (format) {
189  case PNM_PBM:
190  case PNM_PBM_ASCII:
191  sprintf((char *)buffer, "%s %10u %10u\n", format2string(format), width, height);
192  break;
193 
194  case PNM_PGM:
195  case PNM_PGM_ASCII:
196  case PNM_PPM:
197  case PNM_PPM_ASCII:
198  sprintf((char *)buffer, "%s %10u %10u 255\n", format2string(format), width, height);
199  break;
200  default: break;
201  }
202  }
203 
204  switch (format) {
205  case PNM_PGM:
206  case PNM_PGM_ASCII:
207  case PNM_PPM:
208  case PNM_PPM_ASCII: rv += 4; break;
209  default: break;
210  }
211 
212  return rv;
213 }
214 
215 void
217 {
218  FILE *fp = fopen(filename, "wb");
219  if (!fp) {
220  throw Exception("Could not open file for writing");
221  }
222 
223  if (fwrite(buffer_start, buffer_size, 1, fp) != 1) {
224  throw FileWriteException(filename, "Failed to write data");
225  }
226  fclose(fp);
227 }
228 
229 unsigned int
230 PNMWriter::calc_buffer_size()
231 {
232  unsigned int rv = write_header(true);
233 
234  unsigned int num_row_bytes = 0;
235 
236  switch (format) {
237  case PNM_PBM:
238  // full bytes
239  num_row_bytes = width / 8;
240  if ((width % 8) != 0) {
241  // possibly the last non-full byte
242  num_row_bytes += 1;
243  }
244  break;
245 
246  case PNM_PBM_ASCII:
247  // width numbers + width - 1 white spaces + \n
248  num_row_bytes = 2 * width;
249  break;
250 
251  case PNM_PGM: num_row_bytes = width; break;
252 
253  case PNM_PGM_ASCII: num_row_bytes = width * 4; break;
254 
255  case PNM_PPM: num_row_bytes = 3 * width; break;
256 
257  case PNM_PPM_ASCII:
258  // why 13?
259  // 3 + 1 for each number (0 to 255) per component and following whitespace
260  // * 3 three components
261  // = 12
262  // + 1 for an extra white space after each pixel
263  // = 13
264  num_row_bytes = width * 13;
265  break;
266 
267  default: break;
268  }
269 
270  rv += num_row_bytes * height;
271 
272  return rv;
273 }
274 
275 } // end namespace firevision
Base class for exceptions in Fawkes.
Definition: exception.h:36
Could not write to file.
Definition: system.h:69
PNMWriter(PNMFormat format)
Constructor.
Definition: pnm.cpp:46
virtual void set_buffer(colorspace_t cspace, unsigned char *buffer)
Set image buffer.
Definition: pnm.cpp:79
virtual void write()
Write to file.
Definition: pnm.cpp:216
Interface to write images.
Definition: writer.h:32
colorspace_t cspace
The colorspace of the image.
Definition: writer.h:52
virtual void set_filename(const char *filename)
Set filename.
Definition: writer.cpp:102
char * filename
The complete filename.
Definition: writer.h:45
Fawkes library namespace.