Signal/Geometry Processing Library (SPL) 1.1.24 |

pnmCodec.hpp
Go to the documentation of this file.
1 // Copyright (c) 2011 Michael D. Adams
2 // All rights reserved.
3
4 // __START_OF_LICENSE__
5 //
6 // Copyright (c) 2015 Michael D. Adams
7 // All rights reserved.
8 //
9 // This file is part of the Signal Processing Library (SPL).
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 3,
14 // or (at your option) any later version.
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 General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public
22 // License along with this program; see the file LICENSE. If not,
23 // see <http://www.gnu.org/licenses/>.
24 //
25 // __END_OF_LICENSE__
26
32 #ifndef SPL_pnmCodec_hpp
33 #define SPL_pnmCodec_hpp
34
36 //
38
39 #include <SPL/config.hpp>
40 #include <iostream>
41 #include <sstream>
42 #include <cassert>
43 #include <cstdlib>
44
46 //
48
49 namespace SPL {
50
52 //
54
56 enum PnmMagic {
57 pnmMagicInvalid = 0,
58 pnmMagicTxtPbm = 0x5031,
59 pnmMagicTxtPgm = 0x5032,
60 pnmMagicTxtPpm = 0x5033,
61 pnmMagicBinPbm = 0x5034,
62 pnmMagicBinPgm = 0x5035,
63 pnmMagicBinPpm = 0x5036,
64 pnmMagicPam = 0x5037
65 };
66
68 enum PnmType {
69 pnmTypeInvalid = 0,
70 pnmTypePbm,
71 pnmTypePgm,
72 pnmTypePpm
73 };
74
76 enum PnmFmt {
77 pnmFmtInvalid = 0,
78 pnmFmtTxt,
79 pnmFmtBin
80 };
81
83 const int pnmMaxLineLen = 80;
84
86 struct PnmHeader
87 {
89 PnmMagic magic;
90
92 int width;
93
95 int height;
96
98 int maxVal;
99
101 bool sgnd;
102 };
103
107 PnmType pnmGetType(PnmMagic magic);
108
112 PnmFmt pnmGetFmt(PnmMagic magic);
113
117 int pnmMaxValToPrec(int maxVal);
118
122 int pnmGetNumComps(PnmType type);
123
128 inline long pnmOnes(int n)
129 {
130 return (1UL << n) - 1;
131 }
132
134 //
136
140 int pnmGetHeader(std::istream& in, PnmHeader& header);
141
145 int pnmPutHeader(std::ostream& out, PnmHeader& header);
146
150 int pnmGetChar(std::istream& in);
151
155 int pnmGetTxtBit(std::istream& in);
156
160 long pnmGetTxtInt(std::istream& in, bool sgnd, int& status);
161
165 long pnmGetBinInt(std::istream& in, int wordSize, bool sgnd, int& status);
166
170 int pnmPutBinInt(std::ostream& out, int wordSize, bool sgnd, long val);
171
173 // Encoder
175
179 template <class GetData>
180 int pnmEncode(std::ostream& outStream, int width, int height, int numComps,
181 int maxVal, bool sgnd, GetData& getData, bool binaryFormat)
182 {
183 PnmHeader header;
184 if (numComps == 1) {
185 if (maxVal == 1) {
186 header.magic = binaryFormat ? pnmMagicBinPbm : pnmMagicTxtPbm;
187 } else {
188 header.magic = binaryFormat ? pnmMagicBinPgm : pnmMagicTxtPgm;
189 }
190 } else if (numComps == 3) {
191 header.magic = binaryFormat ? pnmMagicBinPpm : pnmMagicTxtPpm;
192 } else {
193 return -1;
194 }
195 header.width = width;
196 header.height = height;
197 header.maxVal = maxVal;
198 header.sgnd = false;
199
200 if (pnmPutHeader(outStream, header)) {
201 return -1;
202 }
203 if (putData(outStream, header, getData)) {
204 return -1;
205 }
206 return 0;
207 }
208
212 template <class GetData>
213 int putData(std::ostream& out, PnmHeader& header, GetData& getData)
214 {
215 int prec = pnmMaxValToPrec(header.maxVal);
216 int fmt = pnmGetFmt(header.magic);
217 PnmType type = pnmGetType(header.magic);
218 int numComps = pnmGetNumComps(type);
219
220 int lineLen = 0;
221 for (int y = header.height - 1; y >= 0; --y) {
222 if (fmt == pnmFmtBin) {
223 if (type == pnmTypePbm) {
224 int val = 0;
225 int numBits = 0;
226 for (int x = 0; x < header.width; ++x) {
227 long b = getData();
228 val = (val << 1) | (b & 1);
229 ++numBits;
230 if (numBits >= 8) {
231 if (!out.put(static_cast<unsigned char>(val))) {
232 return -1;
233 }
234 val = 0;
235 numBits = 0;
236 }
237 }
238 if (numBits > 0) {
239 assert(numBits <= 8);
240 val <<= 8 - numBits;
241 if (!out.put(static_cast<unsigned char>(val))) {
242 return -1;
243 }
244 }
245 } else {
246 for (int x = 0; x < header.width; ++x) {
247 for (int c = 0; c < numComps; ++c) {
248 //long val = img.get(c, x, y);
249 long val = getData();
250 if (pnmPutBinInt(out, prec, header.sgnd, val)) {
251 return -1;
252 }
253 }
254 }
255 }
256 } else {
257 for (int x = 0; x < header.width; ++x) {
258 for (int c = 0; c < numComps; ++c) {
259 //long val = img.get(c, x, y);
260 long val = getData();
261 std::ostringstream buf;
262 buf << val;
263 int n = buf.str().length();
264 if (lineLen && lineLen + n + 2 > pnmMaxLineLen) {
265 out << "\n";
266 lineLen = 0;
267 }
268 if (lineLen && prec > 1) {
269 out << " ";
270 ++lineLen;
271 }
272 out << buf.str();
273 lineLen += n;
274 }
275 }
276 }
277 if (fmt == pnmFmtTxt && lineLen) {
278 out << "\n";
279 lineLen = 0;
280 }
281 }
282
283 return 0;
284 }
285
287 // Decoder
289
293 template <class Initialize>
294 int pnmDecode(std::istream& inStream, Initialize& initialize)
295 {
296 PnmHeader header;
297 if (pnmGetHeader(inStream, header)) {
298 return -1;
299 }
300 #if defined(PNM_DEBUG)
301 std::cerr
302 << "magic " << std::hex << header.magic << " "
303 << std::dec << " width " << header.width << " "
304 << "height " << header.height << " "
305 << "maxVal " << header.maxVal << "\n"
306 ;
307 #endif
308 int numComps = pnmGetNumComps(pnmGetType(header.magic));
309 typename Initialize::PutData putData;
310 initialize(header.width, header.height, numComps, header.maxVal, header.sgnd, putData);
311 if (getData(inStream, header, putData)) {
312 return -1;
313 }
314 return 0;
315 }
316
320 template <class PutData>
321 int getData(std::istream& in, PnmHeader& header, PutData& putData)
322 {
323 PnmType type = pnmGetType(header.magic);
324 PnmFmt fmt = pnmGetFmt(header.magic);
325 int numComps = pnmGetNumComps(type);
326 int prec = pnmMaxValToPrec(header.maxVal);
327 for (int y = header.height - 1; y >= 0; --y) {
328 if (type == pnmTypePbm) {
329 if (fmt == pnmFmtBin) {
330 for (int x = 0; x < header.width;) {
331 int c;
332 if ((c = in.get()) == std::char_traits<char>::eof()) {
333 return -1;
334 }
335 int n = 8;
336 while (n > 0 && x < header.width) {
337 //img.set(0, x, y, (c >> 7) & 1);
338 putData((c >> 7) & 1);
339 c <<= 1;
340 --n;
341 ++x;
342 }
343 }
344 } else {
345 for (int x = 0; x < header.width; ++x) {
346 long val;
347 if ((val = pnmGetTxtBit(in)) < 0) {
348 return -1;
349 }
350 //img.set(0, x, y, val);
351 putData(val);
352 }
353 }
354 } else {
355 if (fmt == pnmFmtBin) {
356 for (int x = 0; x < header.width; ++x) {
357 for (int c = 0; c < numComps; ++c) {
358 long val;
359 int status;
360 if (val = pnmGetBinInt(in, prec, header.sgnd, status),
361 status) {
362 return -1;
363 }
364 //img.set(c, x, y, val);
365 putData(val);
366 }
367 }
368 } else {
369 for (int x = 0; x < header.width; ++x) {
370 for (int c = 0; c < numComps; ++c) {
371 long val;
372 int status;
373 if (val = pnmGetTxtInt(in, header.sgnd, status), status) {
374 return -1;
375 }
376 //img.set(c, x, y, val);
377 putData(val);
378 }
379 }
380 }
381 }
382 }
383 return 0;
384 }
385
387 //
389
390 }
391
392 #endif
SPL
Definition: Arcball.hpp:48
SPL::PnmHeader::sgnd
bool sgnd
The signedness of the sample data.
Definition: pnmCodec.hpp:101
SPL::PnmHeader::height
int height
The image height.
Definition: pnmCodec.hpp:95
SPL::PnmHeader::width
int width
The image width.
Definition: pnmCodec.hpp:92
SPL::PnmHeader
The header information for PNM data.
Definition: pnmCodec.hpp:86
SPL::PnmHeader::magic
PnmMagic magic
The magic number.
Definition: pnmCodec.hpp:89
SPL::PnmHeader::maxVal
int maxVal
The maximum sample value.
Definition: pnmCodec.hpp:98