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
Definition: Arcball.hpp:48
bool sgnd
The signedness of the sample data.
Definition: pnmCodec.hpp:101
int height
The image height.
Definition: pnmCodec.hpp:95
int width
The image width.
Definition: pnmCodec.hpp:92
The header information for PNM data.
Definition: pnmCodec.hpp:86
PnmMagic magic
The magic number.
Definition: pnmCodec.hpp:89
int maxVal
The maximum sample value.
Definition: pnmCodec.hpp:98