IVT
ByteImage.cpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // This file is part of the Integrating Vision Toolkit (IVT).
3 //
4 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
5 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
6 //
7 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are met:
12 //
13 // 1. Redistributions of source code must retain the above copyright
14 // notice, this list of conditions and the following disclaimer.
15 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // 3. Neither the name of the KIT nor the names of its contributors may be
21 // used to endorse or promote products derived from this software
22 // without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
28 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // ****************************************************************************
35 // ****************************************************************************
36 // Filename: ByteImage.cpp
37 // Author: Pedram Azad
38 // Date: 2004
39 // ****************************************************************************
40 // Changes: 24.07.2008, Miguel Bernal Marin
41 // * Added methods LoadFromFilePNM and SaveToFilePNM
42 // ****************************************************************************
43 
44 
45 // ****************************************************************************
46 // Includes
47 // ****************************************************************************
48 
49 #include <new> // for explicitly using correct new/delete operators on VC DSPs
50 
51 #include "ByteImage.h"
52 
53 #include "Helpers/helpers.h"
54 
55 #include <string.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <ctype.h>
59 
60 
61 
62 
63 // ****************************************************************************
64 // Defines
65 // ****************************************************************************
66 
67 // this is a workaround for a bug in OpenCV:
68 // on Mac, if not one byte extra is allocated for the pixel memory
69 // most of the OpenCV functions crash (segmentation fault), such as
70 // cvErode, cvDilate, cvSmooth, ... (after cvCreateImageHeader and
71 // cvSetImageData)
72 #define EXTRA_BYTES 1
73 
74 
75 
76 // ****************************************************************************
77 // Constructors / Destructor
78 // ****************************************************************************
79 
81 {
82  width = 0;
83  height = 0;
84  bytesPerPixel = 0;
85  pixels = 0;
86  type = eGrayScale;
87  m_bOwnMemory = false;
88 }
89 
90 CByteImage::CByteImage(int nImageWidth, int nImageHeight, ImageType imageType, bool bHeaderOnly)
91 {
92  switch (imageType)
93  {
94  case eGrayScale:
95  bytesPerPixel = 1;
96  break;
97 
98  case eRGB24:
99  case eRGB24Split:
100  bytesPerPixel = 3;
101  break;
102  }
103 
104  width = nImageWidth;
105  height = nImageHeight;
106  type = imageType;
107 
108  if (bHeaderOnly)
109  {
110  pixels = 0;
111  m_bOwnMemory = false;
112  }
113  else
114  {
115  pixels = new unsigned char[width * height * bytesPerPixel + EXTRA_BYTES];
116  m_bOwnMemory = true;
117  }
118 }
119 
120 CByteImage::CByteImage(const CByteImage &image, bool bHeaderOnly)
121 {
122  width = image.width;
123  height = image.height;
125  type = image.type;
126 
127  if (bHeaderOnly)
128  {
129  pixels = 0;
130  m_bOwnMemory = false;
131  }
132  else
133  {
134  pixels = new unsigned char[width * height * bytesPerPixel + EXTRA_BYTES];
135  m_bOwnMemory = true;
136  }
137 }
138 
139 CByteImage::CByteImage(const CByteImage *pImage, bool bHeaderOnly)
140 {
141  width = pImage->width;
142  height = pImage->height;
143  bytesPerPixel = pImage->bytesPerPixel;
144  type = pImage->type;
145 
146  if (bHeaderOnly)
147  {
148  pixels = 0;
149  m_bOwnMemory = false;
150  }
151  else
152  {
153  pixels = new unsigned char[width * height * bytesPerPixel + EXTRA_BYTES];
154  m_bOwnMemory = true;
155  }
156 }
157 
159 {
160  FreeMemory();
161 }
162 
163 
164 // ****************************************************************************
165 // Methods
166 // ****************************************************************************
167 
168 void CByteImage::Set(int nImageWidth, int nImageHeight, ImageType imageType, bool bHeaderOnly)
169 {
170  FreeMemory();
171 
172  switch (imageType)
173  {
174  case eGrayScale:
175  bytesPerPixel = 1;
176  break;
177 
178  case eRGB24:
179  case eRGB24Split:
180  bytesPerPixel = 3;
181  break;
182  }
183 
184  width = nImageWidth;
185  height = nImageHeight;
186  type = imageType;
187 
188  if (bHeaderOnly)
189  {
190  pixels = 0;
191  m_bOwnMemory = false;
192  }
193  else
194  {
195  pixels = new unsigned char[width * height * bytesPerPixel + EXTRA_BYTES];
196  m_bOwnMemory = true;
197  }
198 }
199 
200 void CByteImage::FreeMemory()
201 {
202  if (pixels)
203  {
204  if (m_bOwnMemory)
205  delete [] pixels;
206 
207  pixels = 0;
208  m_bOwnMemory = false;
209  }
210 }
211 
212 bool CByteImage::IsCompatible(const CByteImage *pImage) const
213 {
214  return width == pImage->width && height == pImage->height && type == pImage->type;
215 }
216 
217 
218 static int my_strcmpi(const char *pString1, const char *pString2)
219 {
220  for (int i = 0;; i++)
221  {
222  const unsigned char c1 = (unsigned char) toupper((int) pString1[i]);
223  const unsigned char c2 = (unsigned char) toupper((int) pString2[i]);
224 
225  if (c1 == '\0' || c1 != c2)
226  return c1 - c2;
227  }
228 
229  return 0;
230 }
231 
232 bool CByteImage::LoadFromFile(const char *pFileName)
233 {
234  const char *pBeginEnding = pFileName + strlen(pFileName) - 4;
235  if (my_strcmpi(pBeginEnding, ".bmp") == 0)
236  return LoadFromFileBMP(pFileName);
237  else if (my_strcmpi(pBeginEnding, ".pgm") == 0 || my_strcmpi(pBeginEnding, ".ppm") == 0)
238  return LoadFromFilePNM(pFileName);
239 
240  return false;
241 }
242 
243 bool CByteImage::SaveToFile(const char *pFileName) const
244 {
245  const char *pBeginEnding = pFileName + strlen(pFileName) - 4;
246  if (my_strcmpi(pBeginEnding, ".bmp") == 0)
247  return SaveToFileBMP(pFileName);
248  else if (my_strcmpi(pBeginEnding, ".pgm") == 0 || my_strcmpi(pBeginEnding, ".ppm") == 0)
249  return SaveToFilePNM(pFileName);
250 
251  return false;
252 }
253 
254 
255 bool CByteImage::LoadFromFileBMP(const char *pFileName)
256 {
257  const unsigned short MB = 0x4d42;
258 
259  // first free memory, in any case
260  FreeMemory();
261 
262  FILE *f = fopen(pFileName, "rb");
263  if (!f)
264  return false;
265 
266  unsigned char szHeader[4096];
267 
268  if (fread(szHeader, 14, 1, f) != 1)
269  {
270  fclose(f);
271  return false;
272  }
273 
274  myBITMAPFILEHEADER bitmapFileHeader;
275 
276 #ifdef IVT_BIG_ENDIAN
277  bitmapFileHeader.bfType = invert_byte_order_short(*((unsigned short *) (szHeader)));
278  bitmapFileHeader.bfSize = invert_byte_order_int(*((unsigned int *) (szHeader + 2)));
279  bitmapFileHeader.bfReserved1 = invert_byte_order_short(*((unsigned short *) (szHeader + 6)));
280  bitmapFileHeader.bfReserved2 = invert_byte_order_short(*((unsigned short *) (szHeader + 8)));
281  bitmapFileHeader.bfOffBits = invert_byte_order_int(*((unsigned int *) (szHeader + 10)));
282 #else
283  bitmapFileHeader.bfType = *((unsigned short *) (szHeader));
284  bitmapFileHeader.bfSize = *((unsigned int *) (szHeader + 2));
285  bitmapFileHeader.bfReserved1 = *((unsigned short *) (szHeader + 6));
286  bitmapFileHeader.bfReserved2 = *((unsigned short *) (szHeader + 8));
287  bitmapFileHeader.bfOffBits = *((unsigned int *) (szHeader + 10));
288 #endif
289 
290  if (bitmapFileHeader.bfType != MB || bitmapFileHeader.bfReserved1 != 0 || bitmapFileHeader.bfReserved2 != 0 || bitmapFileHeader.bfOffBits >= 4096)
291  {
292  fclose(f);
293  return false;
294  }
295 
296  if (fread(szHeader + 14, bitmapFileHeader.bfOffBits - 14, 1, f) != 1)
297  {
298  fclose(f);
299  return false;
300  }
301 
302  myBITMAPINFOHEADER bitmapInfoHeader;
303  unsigned char *pBitmapInfoHeaderPosition = szHeader + 14;
304 
305 #ifdef IVT_BIG_ENDIAN
306  bitmapInfoHeader.biSize = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition)));
307  bitmapInfoHeader.biWidth = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 4)));
308  bitmapInfoHeader.biHeight = invert_byte_order_int(*((int *) (pBitmapInfoHeaderPosition + 8)));
309  bitmapInfoHeader.biPlanes = invert_byte_order_short(*((unsigned short *) (pBitmapInfoHeaderPosition + 12)));
310  bitmapInfoHeader.biBitCount = invert_byte_order_short(*((unsigned short *) (pBitmapInfoHeaderPosition + 14)));
311  bitmapInfoHeader.biCompression = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 16)));
312  bitmapInfoHeader.biSizeImage = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 20)));
313  bitmapInfoHeader.biXPelsPerMeter = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 24)));
314  bitmapInfoHeader.biYPelsPerMeter = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 28)));
315  bitmapInfoHeader.biClrUsed = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 32)));
316  bitmapInfoHeader.biClrImportant = invert_byte_order_int(*((unsigned int *) (pBitmapInfoHeaderPosition + 36)));
317 #else
318  bitmapInfoHeader.biSize = *((unsigned int *) (pBitmapInfoHeaderPosition));
319  bitmapInfoHeader.biWidth = *((unsigned int *) (pBitmapInfoHeaderPosition + 4));
320  bitmapInfoHeader.biHeight = *((int *) (pBitmapInfoHeaderPosition + 8));
321  bitmapInfoHeader.biPlanes = *((unsigned short *) (pBitmapInfoHeaderPosition + 12));
322  bitmapInfoHeader.biBitCount = *((unsigned short *) (pBitmapInfoHeaderPosition + 14));
323  bitmapInfoHeader.biCompression = *((unsigned int *) (pBitmapInfoHeaderPosition + 16));
324  bitmapInfoHeader.biSizeImage = *((unsigned int *) (pBitmapInfoHeaderPosition + 20));
325  bitmapInfoHeader.biXPelsPerMeter = *((unsigned int *) (pBitmapInfoHeaderPosition + 24));
326  bitmapInfoHeader.biYPelsPerMeter = *((unsigned int *) (pBitmapInfoHeaderPosition + 28));
327  bitmapInfoHeader.biClrUsed = *((unsigned int *) (pBitmapInfoHeaderPosition + 32));
328  bitmapInfoHeader.biClrImportant = *((unsigned int *) (pBitmapInfoHeaderPosition + 36));
329 #endif
330 
331  if ((bitmapInfoHeader.biBitCount != 8 && bitmapInfoHeader.biBitCount != 24 && bitmapInfoHeader.biBitCount != 32) || bitmapInfoHeader.biWidth <= 0)
332  {
333  fclose(f);
334  return false;
335  }
336 
337  if (bitmapInfoHeader.biCompression != 0)
338  {
339  fclose(f);
340  return false;
341  }
342 
343  if (bitmapInfoHeader.biBitCount != 8 && bitmapInfoHeader.biClrUsed > 256)
344  {
345  fclose(f);
346  return false;
347  }
348 
349  // allocate image
350  width = bitmapInfoHeader.biWidth;
351  height = abs(bitmapInfoHeader.biHeight);
352 
353  int nReadBytesPerPixel;
354 
355  const int nTableSize = bitmapInfoHeader.biClrUsed == 0 ? 1024 : 4 * bitmapInfoHeader.biClrUsed;
356  unsigned char index_table[1024];
357  memcpy(index_table, pBitmapInfoHeaderPosition + bitmapInfoHeader.biSize, nTableSize);
358 
359  bool bIndexed = false;
360 
361  if (bitmapInfoHeader.biBitCount == 8)
362  {
363  if (bitmapFileHeader.bfOffBits - 14 - bitmapInfoHeader.biSize != nTableSize)
364  {
365  fclose(f);
366  return false;
367  }
368 
369  bIndexed = false;
370 
371  bool bGrayScale = true;
372 
373  for (int i = 0; i < nTableSize; i += 4)
374  {
375  if (index_table[i] != index_table[i + 1] || index_table[i] != index_table[i + 2])
376  {
377  // contains non grayscale data
378  bIndexed = true;
379  bGrayScale = false;
380  break;
381  }
382 
383  if (index_table[i] != (i >> 2))
384  bIndexed = true;
385  }
386 
387  if (bGrayScale)
388  {
389  type = eGrayScale;
390  bytesPerPixel = 1;
391  nReadBytesPerPixel = 1;
392  }
393  else
394  {
395  type = eRGB24;
396  bytesPerPixel = 3;
397  nReadBytesPerPixel = 1;
398  }
399  }
400  else
401  {
402  switch (bitmapInfoHeader.biBitCount)
403  {
404  case 24:
405  type = eRGB24;
406  bytesPerPixel = 3;
407  nReadBytesPerPixel = 3;
408  break;
409 
410  case 32:
411  type = eRGB24;
412  bytesPerPixel = 3;
413  nReadBytesPerPixel = 4;
414  break;
415 
416  default:
417  fclose(f);
418  return false;
419  break;
420  }
421  }
422 
423  const int padding_bytes = ((width * nReadBytesPerPixel) % 4 == 0) ? 0 : 4 - ((width * nReadBytesPerPixel) % 4);
424 
425  const int nPixels = width * height;
426 
427  // allocate memory
428  pixels = new unsigned char[nPixels * bytesPerPixel + EXTRA_BYTES];
429  unsigned char *pTempBuffer = new unsigned char[(width * nReadBytesPerPixel + padding_bytes) * height + EXTRA_BYTES];
430  m_bOwnMemory = true;
431 
432  // fill pixels from file
433  if (fread(pTempBuffer, (width * nReadBytesPerPixel + padding_bytes) * height, 1, f) != 1)
434  {
435  FreeMemory();
436  fclose(f);
437  delete [] pTempBuffer;
438  return false;
439  }
440 
441  if (bitmapInfoHeader.biHeight < 0)
442  {
443  if (type == eRGB24)
444  {
445  const int write_width_bytes = 3 * width;
446  const int width_bytes = nReadBytesPerPixel * width;
447  const int aligned_width_bytes = width_bytes + padding_bytes;
448 
449  unsigned char *pHelper1 = pixels;
450  unsigned char *pHelper2 = pTempBuffer;
451 
452  if (nReadBytesPerPixel == 1)
453  {
454  // indexed
455  for (int i = 0; i < height; i++)
456  {
457  for (int j = 0, k = 0; j < width_bytes; j++, k += 3)
458  {
459  pHelper1[k] = index_table[pHelper2[j] << 2];
460  pHelper1[k + 1] = index_table[(pHelper2[j] << 2) + 1];
461  pHelper1[k + 2] = index_table[(pHelper2[j] << 2) + 2];
462  }
463 
464  pHelper1 += write_width_bytes;
465  pHelper2 += aligned_width_bytes;
466  }
467  }
468  else
469  {
470  // convert from BGR or BGRA to RGB
471  for (int i = 0; i < height; i++)
472  {
473  for (int j = 0, k = 0; j < width_bytes; j += nReadBytesPerPixel, k += 3)
474  {
475  pHelper1[k] = pHelper2[j + 2];
476  pHelper1[k + 1] = pHelper2[j + 1];
477  pHelper1[k + 2] = pHelper2[j];
478  }
479 
480  pHelper1 += write_width_bytes;
481  pHelper2 += aligned_width_bytes;
482  }
483  }
484  }
485  else if (type == eGrayScale)
486  {
487  const int aligned_width_bytes = width + padding_bytes;
488 
489  unsigned char *pHelper1 = pixels;
490  unsigned char *pHelper2 = pTempBuffer;
491 
492  if (bIndexed)
493  {
494  // indexed
495  for (int i = 0; i < height; i++)
496  {
497  for (int j = 0; j < width; j++)
498  pHelper1[j] = index_table[pHelper2[j << 2]];
499 
500  pHelper1 += width;
501  pHelper2 += aligned_width_bytes;
502  }
503  }
504  else
505  {
506  // just copy
507  for (int i = 0; i < height; i++)
508  {
509  memcpy(pHelper1, pHelper2, width);
510 
511  pHelper1 += width;
512  pHelper2 += aligned_width_bytes;
513  }
514  }
515  }
516  }
517  else
518  {
519  if (type == eRGB24)
520  {
521  const int write_width_bytes = 3 * width;
522  const int width_bytes = nReadBytesPerPixel * width;
523  const int aligned_width_bytes = width_bytes + padding_bytes;
524 
525  unsigned char *pHelper1 = pixels;
526  unsigned char *pHelper2 = pTempBuffer + aligned_width_bytes * height - aligned_width_bytes;
527 
528  if (nReadBytesPerPixel == 1)
529  {
530  // indexed
531  for (int i = 0; i < height; i++)
532  {
533  for (int j = 0, k = 0; j < width_bytes; j++, k += 3)
534  {
535  pHelper1[k] = index_table[pHelper2[j] << 2];
536  pHelper1[k + 1] = index_table[(pHelper2[j] << 2) + 1];
537  pHelper1[k + 2] = index_table[(pHelper2[j] << 2) + 2];
538  }
539 
540  pHelper1 += write_width_bytes;
541  pHelper2 -= aligned_width_bytes;
542  }
543  }
544  else
545  {
546  // convert from BGR or BGRA to RGB, and from bottom-left to top-left
547  for (int i = 0; i < height; i++)
548  {
549  for (int j = 0, k = 0; j < width_bytes; j += nReadBytesPerPixel, k += 3)
550  {
551  pHelper1[k] = pHelper2[j + 2];
552  pHelper1[k + 1] = pHelper2[j + 1];
553  pHelper1[k + 2] = pHelper2[j];
554  }
555 
556  pHelper1 += write_width_bytes;
557  pHelper2 -= aligned_width_bytes;
558  }
559  }
560  }
561  else if (type == eGrayScale)
562  {
563  const int aligned_width_bytes = width + padding_bytes;
564 
565  unsigned char *pHelper1 = pixels;
566  unsigned char *pHelper2 = pTempBuffer + aligned_width_bytes * height - aligned_width_bytes;
567 
568  if (bIndexed)
569  {
570  // indexed
571  for (int i = 0; i < height; i++)
572  {
573  for (int j = 0; j < width; j++)
574  pHelper1[j] = index_table[pHelper2[j] << 2];
575 
576  pHelper1 += width;
577  pHelper2 -= aligned_width_bytes;
578  }
579  }
580  else
581  {
582  // convert from bottom-left to top-left
583  for (int i = 0; i < height; i++)
584  {
585  memcpy(pHelper1, pHelper2, width);
586 
587  pHelper1 += width;
588  pHelper2 -= aligned_width_bytes;
589  }
590  }
591  }
592  }
593 
594  fclose(f);
595  delete [] pTempBuffer;
596 
597  return true;
598 }
599 
600 bool CByteImage::SaveToFileBMP(const char *pFileName) const
601 {
602  if (!pixels || !width || !height)
603  return false;
604 
605  const unsigned short MB = 0x4d42;
606  const int padding_bytes = ((width * bytesPerPixel) % 4 == 0) ? 0 : 4 - ((width * bytesPerPixel) % 4);
607 
608  myBITMAPFILEHEADER bitmapFileHeader;
609  bitmapFileHeader.bfType = MB;
610  bitmapFileHeader.bfReserved1 = 0;
611  bitmapFileHeader.bfReserved2 = 0;
612 
613  myBITMAPINFOHEADER bitmapInfoHeader;
614  bitmapInfoHeader.biSize = 40;
615  bitmapInfoHeader.biWidth = width;
616  bitmapInfoHeader.biHeight = height;
617  bitmapInfoHeader.biPlanes = 1;
618  bitmapInfoHeader.biXPelsPerMeter = 0;
619  bitmapInfoHeader.biYPelsPerMeter = 0;
620  bitmapInfoHeader.biClrUsed = 0;
621  bitmapInfoHeader.biClrImportant = 0;
622 
623  switch (type)
624  {
625  case eGrayScale:
626  bitmapInfoHeader.biBitCount = 8;
627  bitmapInfoHeader.biSizeImage = (width + padding_bytes) * height;
628  bitmapInfoHeader.biCompression = 0;
629  bitmapFileHeader.bfOffBits = 14 + 40 + 1024;
630  bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + bitmapInfoHeader.biSizeImage;
631  break;
632 
633  case eRGB24:
634  case eRGB24Split:
635  bitmapInfoHeader.biBitCount = 24;
636  bitmapInfoHeader.biSizeImage = (width * 3 + padding_bytes) * height;
637  bitmapInfoHeader.biCompression = 0;
638  bitmapFileHeader.bfOffBits = 14 + 40;
639  bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + bitmapInfoHeader.biSizeImage;
640  break;
641 
642  default:
643  return false;
644  break;
645  }
646 
647  FILE *f = fopen(pFileName, "wb");
648  if (!f)
649  return false;
650 
651  unsigned char szHeader[14 + 40];
652  unsigned char *pBitmapInfoHeaderPosition = szHeader + 14;
653 
654 #ifdef IVT_BIG_ENDIAN
655  *((unsigned short *) (szHeader)) = invert_byte_order_short(bitmapFileHeader.bfType);
656  *((unsigned int *) (szHeader + 2)) = invert_byte_order_int(bitmapFileHeader.bfSize);
657  *((unsigned short *) (szHeader + 6)) = invert_byte_order_short(bitmapFileHeader.bfReserved1);
658  *((unsigned short *) (szHeader + 8)) = invert_byte_order_short(bitmapFileHeader.bfReserved2);
659  *((unsigned int *) (szHeader + 10)) = invert_byte_order_int(bitmapFileHeader.bfOffBits);
660 
661  // write bitmap info header to file
662  *((unsigned int *) (pBitmapInfoHeaderPosition)) = invert_byte_order_int(bitmapInfoHeader.biSize);
663  *((unsigned int *) (pBitmapInfoHeaderPosition + 4)) = invert_byte_order_int(bitmapInfoHeader.biWidth);
664  *((unsigned int *) (pBitmapInfoHeaderPosition + 8)) = invert_byte_order_int(bitmapInfoHeader.biHeight);
665  *((unsigned short *) (pBitmapInfoHeaderPosition + 12)) = invert_byte_order_short(bitmapInfoHeader.biPlanes);
666  *((unsigned short *) (pBitmapInfoHeaderPosition + 14)) = invert_byte_order_short(bitmapInfoHeader.biBitCount);
667  *((unsigned int *) (pBitmapInfoHeaderPosition + 16)) = invert_byte_order_int(bitmapInfoHeader.biCompression);
668  *((unsigned int *) (pBitmapInfoHeaderPosition + 20)) = invert_byte_order_int(bitmapInfoHeader.biSizeImage);
669  *((unsigned int *) (pBitmapInfoHeaderPosition + 24)) = invert_byte_order_int(bitmapInfoHeader.biXPelsPerMeter);
670  *((unsigned int *) (pBitmapInfoHeaderPosition + 28)) = invert_byte_order_int(bitmapInfoHeader.biYPelsPerMeter);
671  *((unsigned int *) (pBitmapInfoHeaderPosition + 32)) = invert_byte_order_int(bitmapInfoHeader.biClrUsed);
672  *((unsigned int *) (pBitmapInfoHeaderPosition + 36)) = invert_byte_order_int(bitmapInfoHeader.biClrImportant);
673 #else
674  *((unsigned short *) (szHeader)) = bitmapFileHeader.bfType;
675  *((unsigned int *) (szHeader + 2)) = bitmapFileHeader.bfSize;
676  *((unsigned short *) (szHeader + 6)) = bitmapFileHeader.bfReserved1;
677  *((unsigned short *) (szHeader + 8)) = bitmapFileHeader.bfReserved2;
678  *((unsigned int *) (szHeader + 10)) = bitmapFileHeader.bfOffBits;
679 
680  // write bitmap info header to file
681  *((unsigned int *) (pBitmapInfoHeaderPosition)) = bitmapInfoHeader.biSize;
682  *((unsigned int *) (pBitmapInfoHeaderPosition + 4)) = bitmapInfoHeader.biWidth;
683  *((unsigned int *) (pBitmapInfoHeaderPosition + 8)) = bitmapInfoHeader.biHeight;
684  *((unsigned short *) (pBitmapInfoHeaderPosition + 12)) = bitmapInfoHeader.biPlanes;
685  *((unsigned short *) (pBitmapInfoHeaderPosition + 14)) = bitmapInfoHeader.biBitCount;
686  *((unsigned int *) (pBitmapInfoHeaderPosition + 16)) = bitmapInfoHeader.biCompression;
687  *((unsigned int *) (pBitmapInfoHeaderPosition + 20)) = bitmapInfoHeader.biSizeImage;
688  *((unsigned int *) (pBitmapInfoHeaderPosition + 24)) = bitmapInfoHeader.biXPelsPerMeter;
689  *((unsigned int *) (pBitmapInfoHeaderPosition + 28)) = bitmapInfoHeader.biYPelsPerMeter;
690  *((unsigned int *) (pBitmapInfoHeaderPosition + 32)) = bitmapInfoHeader.biClrUsed;
691  *((unsigned int *) (pBitmapInfoHeaderPosition + 36)) = bitmapInfoHeader.biClrImportant;
692 #endif
693 
694  // write header to file
695  if (fwrite(szHeader, 14 + 40, 1, f) != 1)
696  {
697  fclose(f);
698  return false;
699  }
700 
701  // if 8 bit grayscale then write color table
702  if (type == eGrayScale)
703  {
704  char szColorTable[1024];
705 
706  for (int offset = 0, i = 0; i < 256; i++, offset += 4)
707  {
708  szColorTable[offset] = i;
709  szColorTable[offset + 1] = i;
710  szColorTable[offset + 2] = i;
711  szColorTable[offset + 3] = 0;
712  }
713 
714  // write color table to file
715  if (fwrite(szColorTable, 1024, 1, f) != 1)
716  {
717  fclose(f);
718  return false;
719  }
720  }
721 
722  unsigned char *pTempBuffer = new unsigned char[(width * bytesPerPixel + padding_bytes) * height];
723 
724  if (type == eRGB24)
725  {
726  const int width_bytes = 3 * width;
727 
728  unsigned char *pHelper1 = pTempBuffer;
729  unsigned char *pHelper2 = pixels + width * height * 3 - width_bytes;
730 
731  // convert from RGB to BGR, and from top-left to bottom-left
732  for (int i = 0; i < height; i++)
733  {
734  for (int j = 0; j < width_bytes; j += 3)
735  {
736  pHelper1[j] = pHelper2[j + 2];
737  pHelper1[j + 1] = pHelper2[j + 1];
738  pHelper1[j + 2] = pHelper2[j];
739  }
740 
741  for (int j = width_bytes; j < width_bytes + padding_bytes; j++)
742  pHelper1[j] = 0;
743 
744  pHelper1 += width_bytes + padding_bytes;
745  pHelper2 -= width_bytes;
746  }
747  }
748  else if (type == eRGB24Split)
749  {
750  const int width_bytes = 3 * width;
751 
752  unsigned char *pHelper = pTempBuffer;
753  unsigned char *pHelperR = pixels + width * height - width;
754  unsigned char *pHelperG = pHelperR + width * height;
755  unsigned char *pHelperB = pHelperG + width * height;
756 
757  // convert from RGB to BGR, and from top-left to bottom-left
758  for (int i = 0; i < height; i++)
759  {
760  for (int j = 0, offset = 0; j < width_bytes; j += 3, offset++)
761  {
762  pHelper[j] = pHelperB[offset];
763  pHelper[j + 1] = pHelperG[offset];
764  pHelper[j + 2] = pHelperR[offset];
765  }
766 
767  for (int j = width_bytes; j < width_bytes + padding_bytes; j++)
768  pHelper[j] = 0;
769 
770  pHelper += width_bytes + padding_bytes;
771  pHelperR -= width;
772  pHelperG -= width;
773  pHelperB -= width;
774  }
775  }
776  else if (type == eGrayScale)
777  {
778  unsigned char *pHelper1 = pTempBuffer;
779  unsigned char *pHelper2 = pixels + width * height - width;
780 
781  // convert from top-left to bottom-left
782  for (int i = 0; i < height; i++)
783  {
784  for (int j = 0; j < width; j++)
785  pHelper1[j] = pHelper2[j];
786 
787  for (int j = width; j < width + padding_bytes; j++)
788  pHelper1[j] = 0;
789 
790  pHelper1 += width + padding_bytes;
791  pHelper2 -= width;
792  }
793 
794  }
795 
796  if (fwrite(pTempBuffer, (width * bytesPerPixel + padding_bytes) * height, 1, f) != 1)
797  {
798  delete [] pTempBuffer;
799  fclose(f);
800  return false;
801  }
802 
803  delete [] pTempBuffer;
804  fclose(f);
805 
806  return true;
807 }
808 
809 
810 bool CByteImage::LoadFromFilePNM(const char *pFileName)
811 {
812  // first free memory, in any case
813  FreeMemory();
814 
815  FILE *f = fopen(pFileName, "rb");
816  if (!f)
817  return false;
818 
819  int character, maxVal;
820  char sNumber[16];
821  short idx;
822 
823  character = fgetc(f);
824  if (character != 'P')
825  {
826  fclose(f);
827  return false;
828  }
829 
830  character = fgetc(f);
831  if (character != '5' && character != '6' )
832  {
833  fclose(f);
834  return false;
835  }
836 
837  if (character == '5')
838  {
839  type = eGrayScale;
840  bytesPerPixel = 1;
841  }
842  else
843  {
844  type = eRGB24;
845  bytesPerPixel = 3;
846  }
847 
848  do
849  {
850  // Read whitespaces
851  character = fgetc(f);
852  } while (character == ' ' || character == '\n' || character == '\r');
853 
854  // Skip comments
855  while (character == '#')
856  {
857  while (fgetc(f) != '\n');
858  character = fgetc(f);
859  }
860 
861  // Read width
862  idx = 0;
863  while (character != ' ' && character != '\n' && character != '\r')
864  {
865  sNumber[idx++] =(char) character;
866  character = fgetc(f);
867  }
868  sscanf(sNumber,"%d",&width);
869 
870  do
871  { // Read whitespaces
872  character = fgetc(f);
873  } while (character == ' ' || character == '\n' || character == '\r');
874 
875  // Skip comments
876  while (character == '#')
877  {
878  while (fgetc(f) != '\n');
879  character = fgetc(f);
880  }
881 
882  // Read height
883  idx = 0;
884  while (character != ' ' && character != '\n' && character != '\r') {
885  sNumber[idx++] =(char) character;
886  character = fgetc(f);
887  }
888  sscanf(sNumber,"%d",&height);
889 
890  do
891  {
892  // Read whitespaces
893  character = fgetc(f);
894  } while (character == ' ' || character == '\n' || character == '\r');
895 
896  // Skip comments
897  while (character == '#')
898  {
899  while (fgetc(f) != '\n');
900  character = fgetc(f);
901  }
902 
903  // The maximum color value (Maxval)
904  idx = 0;
905  while (character != ' ' && character != '\n' && character != '\r')
906  {
907  sNumber[idx++] =(char) character;
908  character = fgetc(f);
909  }
910  sscanf(sNumber,"%d",&maxVal);
911 
912  if (maxVal != 255)
913  {
914  fclose(f);
915  return false;
916  }
917 
918  pixels = new unsigned char[width * height * bytesPerPixel + EXTRA_BYTES];
919  m_bOwnMemory = true;
920 
921  if (fread (pixels , width * height * bytesPerPixel, 1, f ) != 1)
922  {
923  FreeMemory();
924  fclose(f);
925  return false;
926  }
927 
928  fclose(f);
929 
930  return true;
931 }
932 
933 bool CByteImage::SaveToFilePNM(const char *pFileName) const
934 {
935  if (!pixels || !width || !height)
936  return false;
937 
938  FILE *f = fopen(pFileName, "wb");
939  if (!f)
940  return false;
941 
942  switch (type)
943  {
944  case eGrayScale:
945  if (fprintf(f,"P5\n%d %d\n255\n", width, height) < 10)
946  {
947  fclose(f);
948  return false;
949  }
950  break;
951 
952  case eRGB24:
953  case eRGB24Split:
954  if (fprintf(f,"P6\n%d %d\n255\n",width , height) < 10)
955  {
956  fclose(f);
957  return false;
958  }
959  break;
960 
961  default:
962  fclose(f);
963  return false;
964  break;
965  }
966 
967  if (type == eGrayScale || type == eRGB24)
968  {
969  if (fwrite(pixels, width * height * bytesPerPixel, 1, f ) != 1)
970  {
971  fclose(f);
972  return false;
973  }
974  }
975  else if (type == eRGB24Split)
976  {
977  const int nPixels = width * height;
978 
979  unsigned char *pTempBuffer = new unsigned char[nPixels * 3];
980  const unsigned char *pHelperR = pixels;
981  const unsigned char *pHelperG = pHelperR + nPixels;
982  const unsigned char *pHelperB = pHelperG + nPixels;
983 
984  for (int i = 0, offset = 0; i < nPixels; i++, offset += 3)
985  {
986  pTempBuffer[offset] = pHelperR[i];
987  pTempBuffer[offset + 1] = pHelperG[i];
988  pTempBuffer[offset + 2] = pHelperB[i];
989  }
990 
991  if (fwrite(pTempBuffer, nPixels * 3, 1, f ) != 1)
992  {
993  delete [] pTempBuffer;
994  fclose(f);
995  return false;
996  }
997 
998  delete [] pTempBuffer;
999  }
1000 
1001  fclose(f);
1002 
1003  return true;
1004 }
ImageType
Enum specifying the supported image types.
Definition: ByteImage.h:86
bool m_bOwnMemory
Flag signaling if memory is to be freed or not.
Definition: ByteImage.h:301
void Set(int nImageWidth, int nImageHeight, ImageType imageType, bool bHeaderOnly=false)
Changes size and type of an image.
Definition: ByteImage.cpp:168
bool LoadFromFile(const char *pFileName)
Loads an image from a file.
Definition: ByteImage.cpp:232
bool SaveToFile(const char *pFileName) const
Saves an image to a file.
Definition: ByteImage.cpp:243
~CByteImage()
The destructor.
Definition: ByteImage.cpp:158
unsigned int invert_byte_order_int(unsigned int x)
Definition: helpers.cpp:89
static int my_strcmpi(const char *pString1, const char *pString2)
Definition: ByteImage.cpp:218
ImageType type
The type of the image.
Definition: ByteImage.h:292
int width
The width of the image in pixels.
Definition: ByteImage.h:257
int height
The height of the image in pixels.
Definition: ByteImage.h:264
CByteImage()
The default constructor.
Definition: ByteImage.cpp:80
#define EXTRA_BYTES
Definition: ByteImage.cpp:72
unsigned char * pixels
The pointer to the the pixels.
Definition: ByteImage.h:283
bool IsCompatible(const CByteImage *pImage) const
Checks whether two images are compatible or not.
Definition: ByteImage.cpp:212
unsigned short invert_byte_order_short(unsigned short x)
Definition: helpers.cpp:99
Data structure for the representation of 8-bit grayscale images and 24-bit RGB (or HSV) color images ...
Definition: ByteImage.h:80
int bytesPerPixel
The number of bytes used for encoding one pixel.
Definition: ByteImage.h:273