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
35using namespace fawkes;
36
37namespace firevision {
38
39/** @class PNMWriter <fvutils/writers/pnm.h>
40 * PNM file writer.
41 */
42
43/** Constructor.
44 * @param format PNM subformat
45 */
46PNMWriter::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 */
61PNMWriter::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
78void
79PNMWriter::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
167const char *
168PNMWriter::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
182unsigned int
183PNMWriter::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
215void
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
229unsigned int
230PNMWriter::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.