KSquare Utilities
BMPImage.cpp
Go to the documentation of this file.
1 /* BMPImage.cpp -- Manages the reading and writing of BMP image files.
2  * Copyright (C) 1994-2011 Kurt Kramer
3  * For conditions of distribution and use, see copyright notice in KKB.h
4  */
5 #include "FirstIncludes.h"
6 
7 
8 #include <algorithm>
9 #include <fstream>
10 #include <functional>
11 #include <iostream>
12 #include <map>
13 #include <string.h>
14 #include <string>
15 #include <vector>
16 #include <stdio.h>
17 #include "MemoryDebug.h"
18 using namespace std;
19 
20 
21 #ifdef WIN32
22 #include <windows.h>
23 #endif
24 
25 
26 #include "BMPImage.h"
27 #include "KKException.h"
28 #include "OSservices.h"
29 #include "Raster.h"
30 using namespace KKB;
31 
32 
33 #ifndef WIN32
34 
35 union BmpImage::WordParts
36 {
37  WORD w;
38  struct
39  {
40  uchar c1;
41  uchar c2;
42  } parts;
43 };
44 
45 
46 union BmpImage::DWordParts
47 {
48  DWORD w;
49  struct
50  {
51  uchar c1;
52  uchar c2;
53  uchar c3;
54  uchar c4;
55  } parts;
56 };
57 
58 
59 
60 union BmpImage::LongParts
61 {
62  LONG l;
63  struct
64  {
65  uchar c1;
66  uchar c2;
67  uchar c3;
68  uchar c4;
69  } parts;
70 };
71 
72 
73 
74 
75 
76 void RotateWORD (WORD& w)
77 {
78  BmpImage::WordParts& wp = (BmpImage::WordParts&)w;
79 
80  BmpImage::WordParts temp = wp;
81 
82  wp.parts.c1 = temp.parts.c2;
83  wp.parts.c2 = temp.parts.c1;
84 } /* RotateWORD */
85 
86 
87 
88 
89 void RotateDWORD (DWORD& w)
90 {
91  BmpImage::DWordParts& wp = (BmpImage::DWordParts&)w;
92 
93  BmpImage::DWordParts temp = wp;
94 
95  wp.parts.c1 = temp.parts.c4;
96  wp.parts.c2 = temp.parts.c3;
97  wp.parts.c3 = temp.parts.c2;
98  wp.parts.c4 = temp.parts.c1;
99 } /* RotateDWORD */
100 
101 
102 
103 
104 void RotateLONG (LONG& l)
105 {
106  BmpImage::LongParts& lp = (BmpImage::LongParts&)l;
107 
108  BmpImage::LongParts temp = lp;
109 
110  lp.parts.c1 = temp.parts.c4;
111  lp.parts.c2 = temp.parts.c3;
112  lp.parts.c3 = temp.parts.c2;
113  lp.parts.c4 = temp.parts.c1;
114 } /* RotateLONG */
115 
116 
117 void WriteWORD (FILE* outFile, WORD w)
118 {
119  RotateWORD (w);
120  fwrite (&w, sizeof (w), 1, outFile);
121 }
122 
123 
124 void WriteDWORD (FILE* outFile, DWORD dw)
125 {
126  RotateDWORD (dw);
127  fwrite (&dw, sizeof (dw), 1, outFile);
128 }
129 
130 
131 
132 void WriteLONG (FILE* outFile, LONG l)
133 {
134  RotateLONG (l);
135  fwrite (&l, sizeof (l), 1, outFile);
136 }
137 
138 
139 void WriteBYTE (FILE* outFile, BYTE b)
140 {
141  fwrite (&b, sizeof (b), 1, outFile);
142 }
143 
144 
145 #endif
146 
147 
148 
149 
151 {
154 };
155 
156 
157 
158 
159 /**
160  *@class BmpImage::CodedPixels
161  *@brief This object is used to help encode the data stored in BMPImage::image into 8 or 4 bit compressed formats used by BMP files. *
162  */
164 {
165 public:
166  CodedPixels (kkint32 _height,
167  kkint32 _width
168  );
169  ~CodedPixels ();
170 
171  void AddPixel (uchar pixel); /*!< This method is called once for each pixel in the BMP image */
172 
173  void EOL (); /*!< This is called once at the end of each row of pixels. */
174 
175  uchar* CreatePixelDataStructure4Bit (kkint32& len); /**< Creates the appropriate compressed data structure for the BMP 4-bit
176  * compressed file format. The length of the structure created will be
177  * returned in the 'len' parameter. The caller will be responsible for
178  * deleting the returned data structure.
179  */
180 
181  uchar* CreatePixelDataStructure8Bit (kkint32& len); /**< Creates the appropriate compressed data structure for the BMP 8-bit
182  * compressed file format. The length of the structure created will be
183  * returned in the 'len' parameter. The caller will be responsible for
184  * deleting the returned data structure.
185  */
186 
187 private:
188  kkint32 height;
189  kkint32 width;
190 
191  kkint32 codesAllocated;
192  kkint32 used;
193 
194  CodePairPtr codes;
195  CodePairPtr top;
196 };
197 
198 
199 
201  kkint32 _width
202  ):
203  height (_height),
204  width (_width),
205  top (NULL)
206 {
207  codesAllocated = height * (width + 4);
208  used = 0;
209 
210  codes = new CodePair[codesAllocated];
211 }
212 
213 
214 
216 {
217  delete codes;
218 }
219 
220 
221 
222 
224 {
225  if (used >= codesAllocated)
226  {
227  // We are exceeding the codes Size.
228  cerr << "CodedPixels::AddPixel *** Error ***, Exceeding codesAllocated." << std::endl;
229  return;
230  }
231 
232  if (!top)
233  {
234  top = &(codes[0]);
235  used++;
236  top->count = 1;
237  top->pixel = pixel;
238  }
239 
240  else if ((pixel != top->pixel) || (top->count == 0))
241  {
242  used++;
243  top++;
244  top->count = 1;
245  top->pixel = pixel;
246  }
247 
248  else
249  {
250  if (top->count >= 254)
251  {
252  used++;
253  top++;
254  top->count = 1;
255  top->pixel = pixel;
256  }
257  else
258  {
259  top->count++;
260  }
261  }
262 } /* AddPixel */
263 
264 
265 
267 {
268  used++;
269  top++;
270  top->count = 0;
271  top->pixel = 0;
272 } /* EOL */
273 
274 
275 
276 
278 {
279  kkint32 buffSize = codesAllocated;
280 
281  uchar* buff = new uchar [buffSize + 4]; // + 4 For Safety
282  memset (buff, 0, codesAllocated);
283 
284 
285  kkint32 curPair = 0;
286  top = &(codes[0]);
287 
288  kkint32 bp = 0;
289 
290  while (curPair < used)
291  {
292  if (bp >= buffSize)
293  {
294  kkint32 newBuffSize = buffSize * 2;
295  uchar* newBuff = new uchar[newBuffSize];
296  memset (newBuff, 0, newBuffSize);
297  memcpy (newBuff, buff, buffSize);
298  delete[] buff;
299  buff = newBuff;
300  newBuff = NULL;
301  buffSize = newBuffSize;
302  }
303 
304 
305  {
306  if ((top->count == 0) && (top->pixel == 0))
307  {
308  // Add End Of Line
309  buff[bp] = 0;
310  bp++;
311  buff[bp] = 0;
312  bp++;
313 
314  curPair++;
315  top++;
316  }
317 
318  else
319  {
320  if (top->count > 254)
321  {
322  buff[bp] = 254;
323  bp++;
324 
325  buff[bp] = top->pixel * 16 + top->pixel;
326  bp++;
327 
328  top->count = top->count - 254;
329  }
330 
331  else
332  {
333  buff[bp] = top->count;
334  bp++;
335 
336  buff[bp] = top->pixel * 16 + top->pixel;
337  bp++;
338 
339  curPair++;
340  top++;
341  }
342  }
343  }
344  }
345 
346  buff[bp] = 0;
347  bp++;
348 
349  buff[bp] = 1;
350  bp++;
351 
352  len = bp;
353  return buff;
354 } /* CreatePixelDataStructure */
355 
356 
357 
359 {
360  kkint32 buffSize = codesAllocated;
361 
362  uchar* buff = new uchar [buffSize + 4]; // + 4 For Safety
363  memset (buff, 0, codesAllocated);
364 
365  kkint32 curPair = 0;
366  top = &(codes[0]);
367 
368  kkint32 bp = 0;
369 
370  while (curPair < used)
371  {
372  if (bp >= (buffSize - 1))
373  {
374  kkint32 newBuffSize = buffSize * 2;
375  uchar* newBuff = new uchar[newBuffSize + 2];
376  if (newBuff == NULL)
377  {
378  KKStr errMsg = "BmpImage::CodedPixels::CreatePixelDataStructure8Bit ***ERROR*** Allocation of 'newBuff' failed.";
379  cerr << std::endl << std::endl << errMsg << std::endl << std::endl;
380  throw KKException (errMsg);
381  }
382 
383  memset (newBuff, 0, newBuffSize);
384  memcpy (newBuff, buff, buffSize);
385  delete[] buff;
386  buff = newBuff;
387  newBuff = NULL;
388  buffSize = newBuffSize;
389  }
390 
391 
392  {
393  if ((top->count == 0) && (top->pixel == 0))
394  {
395  // Add End Of Line
396  buff[bp] = 0;
397  bp++;
398  buff[bp] = 0;
399  bp++;
400 
401  curPair++;
402  top++;
403  }
404 
405  else
406  {
407  if (top->count > 254)
408  {
409  buff[bp] = 254;
410  bp++;
411 
412  buff[bp] = top->pixel;
413  bp++;
414 
415  top->count = top->count - 254;
416  }
417 
418  else
419  {
420  buff[bp] = top->count;
421  bp++;
422 
423  buff[bp] = top->pixel;
424  bp++;
425 
426  curPair++;
427  top++;
428  }
429  }
430  }
431  }
432 
433 
434  buff[bp] = 0;
435  bp++;
436 
437  buff[bp] = 1;
438  bp++;
439 
440  len = bp;
441  return buff;
442 } /* CreatePixelDataStructure */
443 
444 
445 
446 
447 
448 
449 BmpImage::BmpImage (const KKStr& _fileName,
450  bool& successfull
451  ):
452 
453  color (false),
454  fileName (_fileName),
455  red (NULL),
456  image (NULL),
457  blue (NULL),
458  numOfColors (16),
459  palette (NULL),
460  paletteEntries (0)
461 
462 {
463  FILE* inFile = osFOPEN (fileName.Str (), "rb");
464  if (!inFile)
465  {
466  successfull = false;
467  return;
468  }
469 
470  successfull = true;
471 
472  size_t x;
473  kkint32 y;
474 
475  x = fread (&hdr, sizeof (hdr), 1, inFile);
476  if (x <= 0)
477  {
478  successfull = false;
479  fclose (inFile);
480  return;
481  }
482 
483  uchar buff[4];
484  memcpy (buff, &hdr, sizeof (buff));
485  if ((buff[0] == 'B') && (buff[1] == 'M'))
486  {
487  // We have a Bit Map file.
488  }
489  else if ((buff[0] == 137) && (buff[1] == 'P') && (buff[2] == 'N') && (buff[3] == 'G'))
490  {
491  // We are looking at a PNG (Portable Network Graphics) file.
492  cerr << std::endl
493  << "File[" << _fileName << "] is a PNG formatted file." << std::endl
494  << std::endl;
495  successfull = false;
496  fclose (inFile);
497  return;
498  }
499  else
500  {
501  cerr << std::endl
502  << "File[" << _fileName << "] is of a unknown file format." << std::endl
503  << std::endl;
504  successfull = false;
505  fclose (inFile);
506  return;
507  }
508 
509 
510  x = fread (&bmh, sizeof (bmh), 1, inFile);
511  if (x <= 0)
512  {
513  successfull = false;
514  fclose (inFile);
515  return;
516  }
517 
518  if ((bmh.biCompression == BI_RGB) && (bmh.biBitCount == 24))
519  {
520  numOfColors = 16777216;
521  color = true;
522  delete palette;
523  palette = NULL;
524  Load24BitColor (inFile, successfull);
525  fclose (inFile);
526  return;
527  }
528 
529  if ((bmh.biCompression == BI_RGB) && (bmh.biBitCount == 8))
530  {
531  Load8BitColor (inFile, successfull);
532  fclose (inFile);
533  return;
534  }
535 
536  else if ((bmh.biCompression == BI_RGB) || (bmh.biCompression == BI_RLE4))
537  numOfColors = 16;
538 
539  else if (bmh.biBitCount == 1)
540  numOfColors = 16;
541 
542  else
543  numOfColors = 256;
544 
545 
546  paletteEntries = BMIcolorArraySize (bmh);
547  if (paletteEntries < 0)
548  {
549  successfull = false;
550  fclose (inFile);
551  return;
552  }
553 
554  bool imageIsRevGrayscale = false;
555  if (paletteEntries)
556  {
557  palette = new RGBQUAD[paletteEntries];
558  x = fread (palette, sizeof (RGBQUAD), paletteEntries, inFile);
559  imageIsRevGrayscale = ReversedGrayscaleImage ();
560  }
561  else
562  {
563  numOfColors = 256;
564  paletteEntries = 256;
565  palette = new RGBQUAD[paletteEntries];
566  SetUp256BitPalette (palette);
567  }
568 
569  // Lets Build Palette Map
570  for (x = 0; x < 256; x++)
571  paletteMap[x] = 0;
572 
573  if (numOfColors == 16)
574  {
575  for (kkint32 palletIdx = 0; palletIdx < paletteEntries; palletIdx++)
576  {
577  if (imageIsRevGrayscale)
578  y = 255 - palette[palletIdx].rgbGreen;
579  else
580  y = palette[palletIdx].rgbGreen;
581  if (y < 0) y = 0; else if (y > 255) y = 255;
582  paletteMap[palletIdx] = y;
583  }
584  }
585  else
586  {
587  for (kkint32 palletIdx = 0; palletIdx < paletteEntries; palletIdx++)
588  {
589  if (imageIsRevGrayscale)
590  y = 255 - palette[palletIdx].rgbGreen;
591  else
592  y = palette[palletIdx].rgbGreen;
593  if (y < 0) y = 0; else if (y > 255) y = 255;
594  paletteMap[palletIdx] = y;
595  }
596  }
597 
598  delete palette;
599  paletteEntries = 256;
600  palette = new RGBQUAD[paletteEntries];
601  SetUp256BitPalette (palette);
602 
603  kkint32 row;
604 
605  image = new uchar*[bmh.biHeight];
606  for (row = 0; row < bmh.biHeight; row++)
607  {
608  image[row] = new uchar[bmh.biWidth];
609  memset (image[row], 0, bmh.biWidth);
610  }
611 
612  x = fseek (inFile, hdr.bfOffBits, SEEK_SET);
613 
614  if (bmh.biBitCount == 1)
615  {
616  Load1BitColor (inFile, successfull);
617  }
618 
619  else if (bmh.biBitCount == 4)
620  {
621  if (bmh.biCompression == BI_RGB)
622  {
623  Load4BitColor (inFile, successfull);
624  }
625 
626  else if (bmh.biCompression == BI_RLE4)
627  {
628  Load4BitColorCompressed (inFile, successfull);
629  }
630 
631  else
632  {
633  cerr << "***ERROR*** Invalid Compression Mode[" << bmh.biCompression
634  << "] Specified for 4 bit File["
635  << fileName << "]."
636  << std::endl;
637  successfull = false;
638  // WaitForEnter ();
639  }
640  }
641 
642  else if (bmh.biBitCount == 8)
643  {
644  if (bmh.biCompression == BI_RGB)
645  {
646  Load8BitColor (inFile, successfull);
647  }
648 
649  else if (bmh.biCompression == BI_RLE8)
650  {
651  Load8BitColorCompressed (inFile, successfull);
652  }
653 
654  else
655  {
656  cerr << "***ERROR*** Invalid Compression Mode[" << bmh.biCompression
657  << "] Specified for 8 bit File["
658  << fileName << "]."
659  << std::endl;
660  successfull = false;
661  }
662  }
663 
664  else if (bmh.biBitCount == 16)
665  {
666  cerr << "***ERROR*** 16 Bit Not Supported. File[" << fileName << "]." << std::endl;
667  // WaitForEnter ();
668  }
669 
670  else if (bmh.biBitCount == 24)
671  {
672  cerr << "***ERROR*** 24 Bit Not Supported. File[" << fileName << "]." << std::endl;
673  }
674 
675  else if (bmh.biBitCount == 32)
676  {
677  cerr << "***ERROR*** 32 Bit Not Supported. File[" << fileName << "]." << std::endl;
678  // WaitForEnter ();
679  }
680 
681  fclose (inFile);
682 }
683 
684 
685 
686 
688  kkint32 _width,
689  kkint32 _numOfColors
690  ):
691 
692  color (false),
693  fileName (),
694  red (NULL),
695  image (NULL),
696  blue (NULL),
697  numOfColors (_numOfColors),
698  palette (NULL)
699 {
700  InitializeFields (_height, _width);
701 }
702 
703 
704 
705 
706 BmpImage::BmpImage (const Raster& raster):
707  color (false),
708  red (NULL),
709  image (NULL),
710  blue (NULL),
711  palette (NULL)
712 {
713  numOfColors = 256; // kk 2005-03-10
714 
715  color = raster.Color ();
716 
717  InitializeFields (raster.Height (), raster.Width ());
718  fileName = "";
719 
720  kkint32 row;
721  kkint32 col;
722 
723  uchar** rasterData = raster.Rows ();
724  uchar** rasterRed = raster.Red ();
725  uchar** rasterBlue = raster.Blue ();
726 
727  for (row = 0; row < bmh.biHeight; row++)
728  {
729  for (col = 0; col < bmh.biWidth; col++)
730  {
731  image[row][col] = rasterData[row][col];
732  if (color)
733  {
734  red[row][col] = rasterRed [row][col];
735  blue[row][col] = rasterBlue[row][col];
736  }
737  }
738  }
739 }
740 
741 
742 
744 {
745  CleanUpMemory ();
746 }
747 
748 
749 
750 /**
751  *@brief Returns true if BMP file is a a reversed GrayScale Image.
752  *@details The original version in PICES had special checks to detect if a SIPPER image; if
753  * there are issues with this routine suggest comparing with BasiLibrary in PICES.
754  */
755 bool BmpImage::ReversedGrayscaleImage ()
756 {
757  kkint32 x = 0;
758  bool allChannelsSameValue = true;
759  bool alwaysDecending = true; // Reversed images pixel values will always be decending.
760  //kkint32 firstUnbalancedChannel = (kkint32)0;
761 
762  for (x = 0; (x < paletteEntries) && allChannelsSameValue; ++x)
763  {
764  RGBQUAD& p = (palette[x]);
765  allChannelsSameValue = (p.rgbBlue == p.rgbGreen) && (p.rgbBlue == p.rgbRed) && (p.rgbGreen == p.rgbRed);
766  //firstUnbalancedChannel = x;
767  if ((x > 0) && (p.rgbBlue >= palette[x - 1].rgbBlue))
768  alwaysDecending = false;
769  }
770 
771  if (allChannelsSameValue && alwaysDecending && (palette[0].rgbBlue == 255) && (palette[paletteEntries - 1].rgbBlue == 0))
772  return true;
773  else
774  return false;
775 } /* ReversedGrayscaleImage */
776 
777 
778 
779 
780 
781 
782 kkint32 BmpImage::BMIcolorArraySize (BITMAPINFOHEADER& _bmh)
783 
784 {
785  if (_bmh.biBitCount == 0)
786  {
787  return -1;
788  }
789 
790  else if (_bmh.biBitCount == 1)
791  {
792  return 2;
793  }
794 
795  else if (_bmh.biBitCount == 4)
796  {
797  return 16;
798  }
799 
800  else if (_bmh.biBitCount == 8)
801  {
802  if (_bmh.biClrUsed == 0)
803  return 255;
804  else
805  return _bmh.biClrUsed;
806  }
807 
808  else if (_bmh.biBitCount == 16)
809  {
810  if (_bmh.biCompression == BI_RGB)
811  return 0;
812  }
813 
814  else if (_bmh.biBitCount == 24)
815  {
816  return _bmh.biClrUsed;
817  }
818 
819  return -1;
820 }
821 
822 
823 
824 
825 void BmpImage::SetUp4BitPallet ()
826 {
827  delete palette; palette = NULL;
828  paletteEntries = 16;
829  palette = new RGBQUAD[paletteEntries];
830 
831  uchar pixelVal = 255;
832  for (kkint32 x = 0; x < 16; x++)
833  {
834  palette[x].rgbBlue = pixelVal;
835  palette[x].rgbGreen = pixelVal;
836  palette[x].rgbRed = pixelVal;
837  pixelVal = pixelVal - 17;
838  }
839 } /* SetUp4BitPallet*/
840 
841 
842 
843 
844 
845 void BmpImage::SetUp8BitPallet ()
846 {
847  delete palette; palette = NULL;
848  paletteEntries = 256;
849  palette = new RGBQUAD[paletteEntries];
850 
851  uchar pixelVal = 255;
852  for (kkint32 x = 0; x < 256; x++)
853  {
854  palette[x].rgbBlue = pixelVal;
855  palette[x].rgbGreen = pixelVal;
856  palette[x].rgbRed = pixelVal;
857  --pixelVal;
858  }
859 } /* SetUp8BitPallet */
860 
861 
862 
863 
864 void BmpImage::SetUp16BitPallet (RGBQUAD* palette)
865 {
866  palette[0].rgbBlue = 255;
867  palette[0].rgbGreen = 255;
868  palette[0].rgbRed = 255;
869 
870  palette[1].rgbBlue = 219;
871  palette[1].rgbGreen = 219;
872  palette[1].rgbRed = 219;
873 
874  palette[2].rgbBlue = 182;
875  palette[2].rgbGreen = 182;
876  palette[2].rgbRed = 182;
877 
878  palette[3].rgbBlue = 146;
879  palette[3].rgbGreen = 146;
880  palette[3].rgbRed = 146;
881 
882  palette[4].rgbBlue = 109;
883  palette[4].rgbGreen = 109;
884  palette[4].rgbRed = 109;
885 
886  palette[5].rgbBlue = 73;
887  palette[5].rgbGreen = 73;
888  palette[5].rgbRed = 73;
889 
890  palette[6].rgbBlue = 36;
891  palette[6].rgbGreen = 36;
892  palette[6].rgbRed = 36;
893 
894  palette[7].rgbBlue = 0;
895  palette[7].rgbGreen = 0;
896  palette[7].rgbRed = 0;
897 
898  palette[8].rgbBlue = 255;
899  palette[8].rgbGreen = 40;
900  palette[8].rgbRed = 40;
901 
902  palette[9].rgbBlue = 40;
903  palette[9].rgbGreen = 40;
904  palette[9].rgbRed = 255;
905 
906  palette[10].rgbBlue = 40;
907  palette[10].rgbGreen = 210;
908  palette[10].rgbRed = 40;
909 
910  palette[11].rgbBlue = 40;
911  palette[11].rgbGreen = 210;
912  palette[11].rgbRed = 210;
913 
914  palette[12].rgbBlue = 210;
915  palette[12].rgbGreen = 40;
916  palette[12].rgbRed = 40;
917 
918  palette[13].rgbBlue = 210;
919  palette[13].rgbGreen = 40;
920  palette[13].rgbRed = 210;
921 
922  palette[14].rgbBlue = 210;
923  palette[14].rgbGreen = 210;
924  palette[14].rgbRed = 40;
925 
926  palette[15].rgbBlue = 210;
927  palette[15].rgbGreen = 210;
928  palette[15].rgbRed = 210;
929 } /* SetUp16BitPallet */
930 
931 
932 
933 
934 
935 void BmpImage::SetPaletteEntry (kkint32 palletIndex,
936  const PixelValue& pixValue
937  )
938 {
939  if ((palletIndex < 0) || (palletIndex > 255))
940  {
941  // Invalid Entry specified
942  cerr << std::endl << std::endl << std::endl
943  << "BmpImage::SetPaletteEntry Invalid PalletIndex[" << palletIndex << "]" << std::endl
944  << std::endl;
945 
946  return;
947  }
948 
949  if (!palette)
950  {
951  cerr << std::endl << std::endl << std::endl
952  << "BmpImage::SetPaletteEntry The palette is not defined!" << std::endl
953  << std::endl;
954 
955  return;
956  }
957 
958  palette[palletIndex].rgbBlue = pixValue.b;
959  palette[palletIndex].rgbGreen = pixValue.g;
960  palette[palletIndex].rgbRed = pixValue.r;
961 } /* SetPaletteEntry */
962 
963 
964 
965 
966 
967 void BmpImage::SetUp256BitPalette (RGBQUAD* palette)
968 {
969  uchar pixVal;
970 
971  kkint32 x;
972 
973  for (x = 0; x < 256; x++)
974  {
975  pixVal = (uchar)x;
976  palette[x].rgbBlue = pixVal;
977  palette[x].rgbGreen = pixVal;
978  palette[x].rgbRed = pixVal;
979  }
980 } /* SetUp256BitPalette */
981 
982 
983 
984 
985 /**
986  *@brief Returns true if palette is for a grayscale image.
987  */
988 bool GrayScaleImage (RGBQUAD* palette,
989  kkint32 palletSize
990  )
991 {
992  bool isGrayScaleImage = true;
993 
994  for (kkint32 x = 0; ((x < palletSize) && isGrayScaleImage); x++)
995  {
996  kkint32 expectedColor = 255 - x;
997  if ((palette[x].rgbBlue != expectedColor) ||
998  (palette[x].rgbGreen != expectedColor) ||
999  (palette[x].rgbRed != expectedColor)
1000  )
1001  {
1002  isGrayScaleImage = false;
1003  }
1004  }
1005 
1006  return isGrayScaleImage;
1007 } /* GrayScaleImage */
1008 
1009 
1010 
1012  kkint32 _width
1013  )
1014 {
1015  hdr.bfType = 19778;
1016  hdr.bfReserved1 = 0;
1017  hdr.bfReserved2 = 0;
1018  // hdr.bfOffBits = sizeof (bmh)
1019 
1020 
1021  bmh.biSize = sizeof (bmh);
1022  bmh.biWidth = _width;
1023  bmh.biHeight = _height;
1024  bmh.biPlanes = 1;
1025 
1026  paletteEntries = 0;
1027 
1028  AllocateRaster ();
1029 
1030  if (numOfColors <= 16)
1031  {
1032  delete palette; palette = NULL;
1033  bmh.biBitCount = 4;
1034  paletteEntries = 16;
1035  bmh.biCompression = BI_RLE4; // BI_RGB;
1036  palette = new RGBQUAD[paletteEntries];
1037 
1038  SetUp16BitPallet (palette);
1039  }
1040  else
1041  {
1042  delete palette; palette = NULL;
1043  bmh.biBitCount = 8;
1044  paletteEntries = 256;
1045  bmh.biCompression = BI_RLE8; // BI_RGB;
1046  palette = new RGBQUAD[paletteEntries];
1047  SetUp256BitPalette (palette);
1048  }
1049 
1050  bmh.biSizeImage = 0;
1051  bmh.biXPelsPerMeter = 2835;
1052  bmh.biYPelsPerMeter = 2835;
1053  bmh.biClrUsed = 0;
1054  bmh.biClrImportant = 0;
1055 
1056  // BITMAPFILEHEADER hdr;
1057  // BITMAPINFOHEADER bmh;
1058 
1059  hdr.bfOffBits = sizeof (bmh) + sizeof (RGBQUAD) * paletteEntries;
1060 } /* InitializeFields */
1061 
1062 
1063 
1064 
1065 
1067 {
1068 public:
1070  {
1071  public:
1072  bool operator() (const RGBQUAD& left,
1073  const RGBQUAD& right
1074  ) const
1075  {
1076  if (left.rgbRed != right.rgbRed)
1077  return (left.rgbRed < right.rgbRed);
1078 
1079  if (left.rgbGreen != right.rgbGreen)
1080  return (left.rgbGreen < right.rgbGreen);
1081 
1082  return (left.rgbBlue < right.rgbBlue);
1083  }
1084  };
1085 
1086 
1088  {
1089  lastColorsSet = false;
1090  }
1091 
1092  kkint32 NumOfColors () const {return (kkint32)colorsUsed.size ();}
1093 
1095  uchar green,
1096  uchar blue
1097  )
1098  {
1099  RGBQUAD key;
1100  key.rgbRed = red;
1101  key.rgbGreen = green;
1102  key.rgbBlue = blue;
1103  idx = colorsUsed.find (key);
1104  if (idx == colorsUsed.end ())
1105  return -1;
1106  else
1107  return idx->second;
1108  }
1109 
1110 
1111  void AddColor (uchar red,
1112  uchar green,
1113  uchar blue
1114  )
1115  {
1116  if (lastColorsSet && (red == lastRed) && (green == lastGreen) && (blue == lastBlue))
1117  return;
1118 
1119  RGBQUAD key;
1120  key.rgbRed = red;
1121  key.rgbGreen = green;
1122  key.rgbBlue = blue;
1123  idx = colorsUsed.find (key);
1124  if (idx == colorsUsed.end ())
1125  {
1126  kkint32 numEntries = (kkint32)colorsUsed.size ();
1127  colorsUsed.insert (pair<RGBQUAD,kkint32> (key, numEntries));
1128  }
1129 
1130  lastRed = red; lastGreen = green; lastBlue = blue;
1131  lastColorsSet = true;
1132  }
1133 
1134 
1135  void BuildPallet (RGBQUAD*& palette,
1136  kkint32& size
1137  )
1138  {
1139  size = (kkint32)colorsUsed.size ();
1140  delete palette; palette = NULL;
1141  if (size < 1)
1142  return;
1143 
1144  palette = new RGBQUAD[size];
1145  for (idx = colorsUsed.begin (); idx != colorsUsed.end (); idx++)
1146  {
1147  palette[idx->second] = idx->first;
1148  }
1149  }
1150 
1151 private:
1152  map<RGBQUAD, kkint32, RGBQUAD_Pred> colorsUsed;
1153  map<RGBQUAD, kkint32, RGBQUAD_Pred>::iterator idx;
1154 
1155  bool lastColorsSet;
1156  uchar lastRed;
1157  uchar lastGreen;
1158  uchar lastBlue;
1159 }; /* PalletBuilder */
1160 
1161 
1162 
1163 
1164 
1165 
1166 BmpImage::PalletBuilderPtr BmpImage::BuildPalletFromRasterData ()
1167 {
1168  PalletBuilderPtr palletBuilder = new PalletBuilder ();
1169 
1170  kkint32 row, col;
1171  uchar* rowRed = NULL;
1172  uchar* rowGreen = NULL;
1173  uchar* rowBlue = NULL;
1174 
1175  for (row = 0; row < bmh.biHeight; row++)
1176  {
1177  rowRed = red [row];
1178  rowGreen = image[row];
1179  rowBlue = blue [row];
1180 
1181  for (col = 0; col < bmh.biWidth; col++)
1182  {
1183  palletBuilder->AddColor (rowRed[col], rowGreen[col], rowBlue[col]);
1184  }
1185  }
1186 
1187  palletBuilder->BuildPallet (palette, paletteEntries);
1188  return palletBuilder;
1189 } /* BuildPalletFromRasterData */
1190 
1191 
1192 
1193 
1195 {
1196  if (palette)
1197  delete palette;
1198 
1199  numOfColors = 16;
1200  paletteEntries = 16;
1201  palette = new RGBQUAD[paletteEntries];
1202  SetUp16BitPallet (palette);
1203 }
1204 
1205 
1206 
1207 
1209 {
1210  if (palette)
1211  delete palette;
1212 
1213  numOfColors = 256;
1214  paletteEntries = 256;
1215  palette = new RGBQUAD[paletteEntries];
1216  SetUp256BitPalette (palette);
1217 }
1218 
1219 
1220 
1221 
1222 
1223 #ifdef WIN32
1225 {
1234 };
1235 
1236 #else
1237 struct BmpImage::Bmp1BitRec
1238 {
1239  uchar pix1: 1;
1240  uchar pix2: 1;
1241  uchar pix3: 1;
1242  uchar pix4: 1;
1243  uchar pix5: 1;
1244  uchar pix6: 1;
1245  uchar pix7: 1;
1246  uchar pix8: 1;
1247 };
1248 #endif
1249 
1250 
1251 
1252 void BmpImage::Load1BitColor (FILE* inFile,
1253  bool& successfull
1254  )
1255 {
1256  successfull = true;
1257 
1258  kkuint32 bmpRowWidthInBytes = bmh.biWidth / 8;
1259 
1260  while ((bmpRowWidthInBytes % 2) > 0)
1261  {
1262  bmpRowWidthInBytes++;
1263  }
1264 
1265  Bmp1BitRec* packedRowData = new Bmp1BitRec [bmpRowWidthInBytes];
1266  uchar* rowData = new uchar [bmpRowWidthInBytes * 8];
1267 
1268  Bmp1BitRec b;
1269  kkuint32 byteNum;
1270  kkint32 col;
1271  kkint32 row;
1272  size_t x;
1273 
1274  for (row = bmh.biHeight - 1; row >= 0; row--)
1275  {
1276  x = fread (packedRowData, 1, bmpRowWidthInBytes, inFile);
1277  if (x < bmpRowWidthInBytes)
1278  {
1279  successfull = false;
1280  cerr << "***ERROR*** BmpImage::Load1BitColor Error Reading File." << std::endl;
1281  return;
1282  }
1283 
1284  col = 0;
1285 
1286  for (byteNum = 0; byteNum < x; byteNum++)
1287  {
1288  b = packedRowData[byteNum];
1289 
1290  rowData[col + 0] = b.pix1;
1291  rowData[col + 1] = b.pix2;
1292  rowData[col + 2] = b.pix3;
1293  rowData[col + 3] = b.pix4;
1294  rowData[col + 4] = b.pix5;
1295  rowData[col + 5] = b.pix6;
1296  rowData[col + 6] = b.pix7;
1297  rowData[col + 7] = b.pix8;
1298 
1299  col = col + 8;
1300  }
1301 
1302  for (col = 0; col < bmh.biWidth; col++)
1303  {
1304  x = paletteMap[rowData[col]];
1305  SetPixelValue (row, col, paletteMap[rowData[col]]);
1306  }
1307  }
1308 
1310 
1311  delete[] rowData;
1312  delete[] packedRowData;
1313 } /* Load1BitColor */
1314 
1315 
1316 
1317 
1319 {
1320  kkint32 oldRow;
1321 
1322  kkint32 newRow;
1323 
1324  kkint32 newHeight = bmh.biHeight + 6;
1325  kkint32 newWidth = bmh.biWidth + 6;
1326 
1327 
1328  uchar** newImage = new uchar*[newHeight];
1329  uchar** newRed = NULL;
1330  uchar** newBlue = NULL;
1331  if (color)
1332  {
1333  newRed = new uchar*[newHeight];
1334  newBlue = new uchar*[newHeight];
1335  }
1336 
1337  for (newRow = 0; newRow < newHeight; newRow++)
1338  {
1339  newImage[newRow] = new uchar[newWidth];
1340  memset (newImage[newRow], 0, newWidth);
1341  if (color)
1342  {
1343  newRed [newRow] = new uchar[newWidth];
1344  newBlue[newRow] = new uchar[newWidth];
1345  memset (newRed [newRow], 0, newWidth);
1346  memset (newBlue [newRow], 0, newWidth);
1347  }
1348  }
1349 
1350  newRow = 3;
1351  for (oldRow = 0; oldRow < bmh.biHeight; oldRow++)
1352  {
1353  memcpy ((newImage[newRow] + 3), image[oldRow], bmh.biWidth);
1354  if (color)
1355  {
1356  memcpy ((newRed[newRow] + 3), red [oldRow], bmh.biWidth);
1357  memcpy ((newBlue[newRow] + 3), blue[oldRow], bmh.biWidth);
1358  }
1359  newRow++;
1360  }
1361 
1362  for (oldRow = 0; oldRow < bmh.biHeight; oldRow++)
1363  {
1364  delete image[oldRow];
1365  image[oldRow] = NULL;
1366  if (color)
1367  {
1368  delete red [oldRow]; red [oldRow] = NULL;
1369  delete blue[oldRow]; blue[oldRow] = NULL;
1370  }
1371  }
1372  delete image;
1373  delete red;
1374  delete blue;
1375 
1376  image = newImage;
1377  if (color)
1378  {
1379  red = newRed; newRed = NULL;
1380  blue = newBlue; newBlue = NULL;
1381  }
1382  bmh.biHeight = newHeight;
1383  bmh.biWidth = newWidth;
1384 } /* RealocateForBiggerScreen */
1385 
1386 
1387 
1388 
1389 
1390 
1391 #ifdef WIN32
1392 
1394 {
1397 };
1398 
1399 #else
1400 struct BmpImage::Bmp4BitRecs
1401 {
1402  uchar pix1: 4;
1403  uchar pix2: 4;
1404 };
1405 
1406 #endif
1407 
1408 
1409 
1410 
1411 
1412 void BmpImage::Load4BitColor (FILE* inFile,
1413  bool& successfull
1414  )
1415 {
1416  successfull = true;
1417  kkuint32 bmpRowWidthInBytes = (bmh.biWidth + 1) / 2;
1418 
1419  kkint32 paddingBytes = bmpRowWidthInBytes % 4;
1420  if (paddingBytes != 0)
1421  paddingBytes = 4 - paddingBytes;
1422 
1423  bmpRowWidthInBytes = bmpRowWidthInBytes + paddingBytes;
1424 
1425  size_t x = sizeof (Bmp4BitRecs);
1426 
1427  Bmp4BitRecs* rowData = new Bmp4BitRecs [bmpRowWidthInBytes];
1428 
1429  kkint32 row;
1430 
1431  for (row = bmh.biHeight - 1; row >= 0; row--)
1432  {
1433  x = fread (rowData, sizeof (Bmp4BitRecs), bmpRowWidthInBytes, inFile);
1434 
1435  if (x < bmpRowWidthInBytes)
1436  {
1437  successfull = false;
1438  cerr << "***ERROR*** BmpImage::Load4BitColor Error Reading File" << std::endl;
1439  return;
1440  }
1441 
1442  kkint32 col;
1443 
1444  for (col = 0; col < bmh.biWidth; col++)
1445  {
1446  kkint32 offset = col / 2;
1447 
1448  uchar nextPixel;
1449 
1450  if ((col % 2) == 0)
1451  {
1452  nextPixel = rowData[offset].pix1;
1453  }
1454  else
1455  {
1456  nextPixel = rowData[offset].pix2;
1457  }
1458 
1459  SetPixelValue (row, col, paletteMap[nextPixel]);
1460  }
1461  }
1462 
1463  delete[] rowData;
1464 } /* Load4BitColor */
1465 
1466 
1467 
1468 
1469 
1470 
1471 void BmpImage::Load8BitColor (FILE* inFile,
1472  bool& successfull
1473  )
1474 {
1475  //cout << "BmpImage::Load8BitColor" << std::endl;
1476  successfull = true;
1477  color = true;
1478  numOfColors = 256;
1479  paletteEntries = numOfColors;
1480  AllocateRaster ();
1481 
1482  fseek (inFile, sizeof (hdr) + sizeof (bmh), SEEK_SET);
1483  fread (palette, sizeof (RGBQUAD), paletteEntries, inFile);
1484 
1485 
1486 /*
1487  cout << std::endl;
1488  for (x = 0; x < paletteEntries; x++)
1489  cout << x << "\t" << (kkuint32)palette[x].rgbRed
1490  << "\t" << (kkuint32)palette[x].rgbGreen
1491  << "\t" << (kkuint32)palette[x].rgbBlue
1492  << std::endl;
1493  osWaitForEnter ();
1494 */
1495 
1496  kkuint32 bmpRowWidthInBytes = bmh.biWidth;
1497  kkuint32 paddingBytes = bmpRowWidthInBytes % 4;
1498  if (paddingBytes != 0)
1499  paddingBytes = 4 - paddingBytes;
1500 
1501  bmpRowWidthInBytes = bmpRowWidthInBytes + paddingBytes;
1502 
1503  fseek (inFile, hdr.bfOffBits, SEEK_SET);
1504 
1505  uchar* rowData = new uchar[bmpRowWidthInBytes];
1506 
1507  kkint32 row;
1508 
1509  for (row = bmh.biHeight - 1; row >= 0; row--)
1510  {
1511  memset (rowData, 0, bmpRowWidthInBytes);
1512  size_t buffRead = fread (rowData, 1, bmpRowWidthInBytes, inFile);
1513  if (buffRead < bmpRowWidthInBytes)
1514  {
1515  cerr << std::endl
1516  << "***ERROR*** BmpImage::Load8BitColor, Error Reading File" << std::endl
1517  << std::endl;
1518  successfull = false;
1519  delete[] rowData; rowData = NULL;
1520  return;
1521  }
1522 
1523  kkint32 col;
1524 
1525  for (col = 0; col < bmh.biWidth; col++)
1526  {
1527  kkint32 palletIdx = rowData[col];
1528 
1529  //cout << "RowData" << "\t" << col << "\t" << palletIdx << "\t" << (kkuint32)(palette[palletIdx].rgbGreen) << std::endl;
1530  blue [row][col] = palette[palletIdx].rgbBlue;
1531  image [row][col] = palette[palletIdx].rgbGreen;
1532  red [row][col] = palette[palletIdx].rgbRed;
1533  }
1534  }
1535 
1536  successfull = true;
1537 
1538  delete[] rowData; rowData = NULL;
1539 
1540 } /* Load8BitColor */
1541 
1542 
1543 
1544 
1545 void BmpImage::Load4BitColorCompressed (FILE* inFile,
1546  bool& successfull
1547  )
1548 {
1549  successfull = true;
1550  kkint32 x;
1551 
1552  size_t imageBuffSize = bmh.biSizeImage;
1553 
1554  uchar* imageBuff = new uchar[imageBuffSize];
1555 
1556  size_t buffRead = fread (imageBuff, sizeof (uchar), imageBuffSize, inFile);
1557 
1558  if (buffRead < imageBuffSize)
1559  {
1560  cerr << "***ERROR*** BmpImage::Load4BitColorCompressed *** Error ***, Invalid File Format." << std::endl;
1561  successfull = false;
1562  return;
1563  }
1564 
1565  kkint32 col = 0;
1566  kkint32 row = bmh.biHeight - 1;
1567 
1568  size_t ifIDX = 0;
1569 
1570  while (ifIDX < imageBuffSize)
1571  {
1572  if (imageBuff[ifIDX] == 0)
1573  {
1574  // We have an Escape Sequence.
1575  ifIDX++;
1576 
1577  if (imageBuff[ifIDX] == 0)
1578  {
1579  // End of Row.
1580  row--;
1581  col = 0;
1582  ifIDX++;
1583  }
1584 
1585  else if (imageBuff[ifIDX] == 1)
1586  {
1587  // End of BitMap
1588 
1589  ifIDX = imageBuffSize;
1590  }
1591 
1592  else if (imageBuff[ifIDX] == 2)
1593  {
1594  ifIDX++;
1595  col = col + imageBuff[ifIDX];
1596 
1597  ifIDX++;
1598  row = row + imageBuff[ifIDX];
1599 
1600  ifIDX++;
1601  }
1602 
1603  else
1604  {
1605  // We have Absolute Mode
1606  kkint32 len = imageBuff[ifIDX];
1607  ifIDX++;
1608 
1609  for (x = 0; x < len;)
1610  {
1611  uchar pix1 = imageBuff[ifIDX] / 16;
1612  uchar pix2 = imageBuff[ifIDX] % 16;
1613  SetPixelValue (row, col, paletteMap[pix1]);
1614  x++;
1615  col++;
1616 
1617  if (x < len)
1618  {
1619  SetPixelValue (row, col, paletteMap[pix2]);
1620  x++;
1621  col++;
1622  }
1623 
1624  ifIDX++;
1625  }
1626 
1627  if (((len + 1) / 2) % 2 != 0)
1628  ifIDX++;
1629  }
1630  }
1631 
1632  else
1633  {
1634  // We have a RLE
1635  kkint32 len = imageBuff[ifIDX];
1636  ifIDX++;
1637 
1638  uchar pix1 = imageBuff[ifIDX] / 16;
1639  uchar pix2 = imageBuff[ifIDX] % 16;
1640 
1641  for (x = 0; x < len;)
1642  {
1643  SetPixelValue (row, col, paletteMap[pix1]);
1644  x++;
1645  col++;
1646 
1647  if (x < len)
1648  {
1649  SetPixelValue (row, col, paletteMap[pix2]);
1650  x++;
1651  col++;
1652  }
1653  }
1654 
1655  ifIDX++;
1656  }
1657  }
1658 
1659  delete[] imageBuff;
1660 } /* Load4BitColorCompressed */
1661 
1662 
1663 
1664 
1665 
1666 void BmpImage::Load8BitColorCompressed (FILE* inFile,
1667  bool& successfull
1668  )
1669 {
1670  kkint32 x;
1671 
1672  successfull = true;
1673 
1674  kkuint32 imageBuffSize = bmh.biSizeImage;
1675 
1676  uchar* imageBuff = new uchar[imageBuffSize];
1677 
1678  size_t buffRead = fread (imageBuff, sizeof (uchar), imageBuffSize, inFile);
1679 
1680  if (buffRead < imageBuffSize)
1681  {
1682  cerr << "***ERROR***, Load4BitColorCompressed *** Error ***, Invalid File Format." << std::endl;
1683  successfull = false;
1684  return;
1685  }
1686 
1687  kkint32 col = 0;
1688  kkint32 row = bmh.biHeight - 1;
1689 
1690  kkuint32 ifIDX = 0;
1691 
1692  while (ifIDX < imageBuffSize)
1693  {
1694  if (imageBuff[ifIDX] == 0)
1695  {
1696  // We have an Escape Sequence.
1697  ifIDX++;
1698 
1699  if (imageBuff[ifIDX] == 0)
1700  {
1701  // End of Row.
1702  row--;
1703  col = 0;
1704  ifIDX++;
1705  }
1706 
1707  else if (imageBuff[ifIDX] == 1)
1708  {
1709  // End of BitMap
1710 
1711  ifIDX = imageBuffSize;
1712  }
1713 
1714  else if (imageBuff[ifIDX] == 2)
1715  {
1716  ifIDX++;
1717  col = col + imageBuff[ifIDX];
1718 
1719  ifIDX++;
1720  row = row + imageBuff[ifIDX];
1721 
1722  ifIDX++;
1723  // Insert Spaces
1724  }
1725 
1726  else
1727  {
1728  // We have Absolute Mode
1729  kkint32 len = imageBuff[ifIDX];
1730  ifIDX++;
1731 
1732  for (x = 0; x < len;)
1733  {
1734  SetPixelValue (row, col, paletteMap[imageBuff[ifIDX]]);
1735  x++;
1736  col++;
1737  ifIDX++;
1738  }
1739 
1740  if ((len % 2) != 0)
1741  ifIDX++;
1742  }
1743  }
1744 
1745  else
1746  {
1747  // We have a RLE
1748  kkint32 len = imageBuff[ifIDX];
1749  ifIDX++;
1750 
1751  kkint32 pixelVal = paletteMap[imageBuff[ifIDX]];
1752 
1753  if (pixelVal == 0)
1754  {
1755  col = col + len;
1756  }
1757  else
1758  {
1759  for (x = 0; x < len;)
1760  {
1761  SetPixelValue (row, col, pixelVal);
1762  x++;
1763  col++;
1764  }
1765  }
1766 
1767  ifIDX++;
1768  }
1769  }
1770 
1771  delete[] imageBuff;
1772 } /* Load8BitColorCompressed */
1773 
1774 
1775 
1776 
1777 
1779 {
1783 };
1784 
1785 
1786 
1787 
1788 void BmpImage::Load24BitColor (FILE* inFile,
1789  bool& successfull
1790  )
1791 {
1792  successfull = true;
1793  color = true;
1794  AllocateRaster ();
1795 
1796  kkuint32 bmpRowWidthInBytes = bmh.biWidth * 3;
1797  kkuint32 paddingBytes = bmpRowWidthInBytes % 4;
1798  if (paddingBytes != 0)
1799  paddingBytes = 4 - paddingBytes;
1800 
1801  bmpRowWidthInBytes = bmpRowWidthInBytes + paddingBytes;
1802 
1803  fseek (inFile, hdr.bfOffBits, SEEK_SET);
1804 
1805  uchar* rowData = new uchar[bmpRowWidthInBytes];
1806 
1807  kkint32 row;
1808 
1809  for (row = bmh.biHeight - 1; row >= 0; row--)
1810  {
1811  memset (rowData, 0, bmpRowWidthInBytes);
1812  size_t buffRead = fread (rowData, 1, bmpRowWidthInBytes, inFile);
1813  if (buffRead < bmpRowWidthInBytes)
1814  {
1815  cerr << std::endl
1816  << "***ERROR*** BmpImage::Load24BitColor, Error Reading File" << std::endl
1817  << std::endl;
1818  successfull = false;
1819  delete[] rowData; rowData = NULL;
1820  return;
1821  }
1822 
1823  kkint32 col;
1824 
1825  for (col = 0; col < bmh.biWidth; col++)
1826  {
1827  kkint32 offset = col * 3;
1828  blue [row][col] = rowData[offset];
1829  image [row][col] = rowData[offset + 1];
1830  red [row][col] = rowData[offset + 2];
1831  }
1832  }
1833 
1834  successfull = true;
1835 
1836  delete[] rowData; rowData = NULL;
1837 } /* Load24BitColor */
1838 
1839 
1840 
1841 
1842 void BmpImage::AllocateRaster ()
1843 {
1844  CleanUpMemory ();
1845 
1846  if (paletteEntries > 1000000)
1847  {
1848  cerr << std::endl << std::endl
1849  << "BmpImage::AllocateRaster ***ERROR*** paletteEntries[" << paletteEntries << "] Is a unreasonable value." << std::endl
1850  << std::endl;
1851  paletteEntries = 0;
1852  }
1853 
1854  if (paletteEntries > 0)
1855  palette = new RGBQUAD[paletteEntries];
1856 
1857  kkint32 row;
1858 
1859  image = new uchar*[bmh.biHeight];
1860  if (color)
1861  {
1862  red = new uchar*[bmh.biHeight];
1863  blue = new uchar*[bmh.biHeight];
1864  }
1865 
1866  for (row = 0; row < bmh.biHeight; row++)
1867  {
1868  image[row] = new uchar[bmh.biWidth];
1869  memset (image[row], 0, bmh.biWidth);
1870  if (color)
1871  {
1872  red[row] = new uchar[bmh.biWidth];
1873  blue[row] = new uchar[bmh.biWidth];
1874  memset (red [row], 0, bmh.biWidth);
1875  memset (blue[row], 0, bmh.biWidth);
1876  }
1877  }
1878 } /* AllocateRaster */
1879 
1880 
1881 
1882 
1883 void BmpImage::CleanUpMemory ()
1884 {
1885  kkint32 x = 0;
1886  if (image)
1887  {
1888  for (x = bmh.biHeight - 1; x >= 0; x--)
1889  {
1890  delete image[x];
1891  image[x] = NULL;
1892  }
1893  delete image;
1894  image = NULL;
1895  }
1896 
1897  if (red)
1898  {
1899  // If red exists then blue must exists.
1900 
1901  for (x = bmh.biHeight - 1; x >= 0; x--)
1902  {
1903  delete red [x]; red [x] = NULL;
1904  delete blue[x]; blue[x] = NULL;
1905  }
1906 
1907  delete red; red = NULL;
1908  delete blue; blue = NULL;
1909  }
1910 
1911  delete palette; palette = NULL;
1912 } /* CleanUpMemory */
1913 
1914 
1915 
1916 
1918 {
1919  kkint32 newCol;
1920  kkint32 newHeight = bmh.biHeight / 2;
1921  kkint32 newWidth = bmh.biWidth / 2;
1922  kkint32 newRow;
1923 
1924  kkint32 oldCol;
1925  kkint32 oldRow;
1926 
1927  uchar** newImage = new uchar*[newHeight];
1928  for (newRow = 0; newRow < newHeight; newRow++)
1929  {
1930  oldRow = newRow * 2;
1931 
1932  newImage[newRow] = new uchar[newWidth];
1933 
1934  for (newCol = 0; newCol < newWidth; newCol++)
1935  {
1936  oldCol = newCol * 2;
1937  newImage[newRow][newCol] = image[oldRow][oldCol];
1938  }
1939  }
1940 
1941  for (oldRow = 0; oldRow < bmh.biHeight; oldRow++)
1942  {
1943  delete image[oldRow];
1944  image[oldRow] = NULL;
1945  }
1946 
1947  delete image;
1948 
1949  image = newImage;
1950 
1951  bmh.biHeight = newHeight;
1952  bmh.biWidth = newWidth;
1953 } /* DownSize */
1954 
1955 
1956 
1957 
1959  kkint32 col)
1960 {
1961  return image[row][col];
1962 }
1963 
1964 
1965 
1966 
1968  kkint32 col,
1969  kkint32 pixel
1970  )
1971 {
1972  if (pixel < 0)
1973  {
1974  cerr << "BmpImage::SetPixelValue ***ERROR*** pixel[" << pixel << "] out of range. Needs to be in range of 0..255." << std::endl;
1975  pixel = 0;
1976  }
1977  else if (pixel > 255)
1978  {
1979  cerr << "BmpImage::SetPixelValue ***ERROR*** pixel[" << pixel << "] out of range. Needs to be in range of 0..255." << std::endl;
1980  pixel = 255;
1981  }
1982 
1983  if ((row < 0) || (row >= bmh.biHeight))
1984  {
1985  cerr << "BmpImage::SetPixelValue *** Error ***, Row[" << row
1986  << "] out of range[0-" << bmh.biHeight << "]."
1987  << std::endl;
1988  return;
1989  }
1990 
1991  if ((col < 0) || (col >= bmh.biWidth))
1992  {
1993  cerr << "BmpImage::SetPixelValue *** Error ***, Col[" << col
1994  << "] out of range[0-" << bmh.biWidth << "]."
1995  << std::endl;
1996  return;
1997  }
1998  image[row][col] = (uchar)pixel;
1999 } /* SetPixelValue */
2000 
2001 
2002 
2003 
2005 {
2006  kkint32 row;
2007  kkint32 col;
2008 
2009  kkint32 height = Height ();
2010  kkint32 width = Width ();
2011 
2012  if (height < 6)
2013  return true;
2014 
2015  if (width < 6)
2016  return true;
2017 
2018 
2019  uchar* row0 = image[0];
2020  uchar* row1 = image[1];
2021  uchar* row2 = image[2];
2022 
2023  uchar* rowL0 = image[height - 3];
2024  uchar* rowL1 = image[height - 2];
2025  uchar* rowL2 = image[height - 1];
2026 
2027 
2028  for (col = 0; col < width; col++)
2029  {
2030  if ((row0[col] > 0) ||
2031  (row1[col] > 0) ||
2032  (row2[col] > 0) ||
2033  (rowL0[col] > 0) ||
2034  (rowL1[col] > 0) ||
2035  (rowL2[col] > 0)
2036  )
2037  return true;
2038  }
2039 
2040  kkint32 lastCol0 = width - 3;
2041  kkint32 lastCol1 = width - 2;
2042  kkint32 lastCol2 = width - 1;
2043 
2044  kkint32 lastRowToCheck = height - 3;
2045 
2046  for (row = 3; row < lastRowToCheck; row++)
2047  {
2048  if ((image[row][0] > 0) ||
2049  (image[row][1] > 0) ||
2050  (image[row][2] > 0) ||
2051  (image[row][lastCol0] > 0) ||
2052  (image[row][lastCol1] > 0) ||
2053  (image[row][lastCol2] > 0)
2054  )
2055  return true;
2056  }
2057 
2058  return false;
2059 } /* EdgePixels */
2060 
2061 
2062 
2064 {
2065  kkint32 col = 0;
2066  kkint32 row = 0;
2067  kkint32 x;
2068 
2069 
2070  bool* potVertLine = new bool[bmh.biWidth];
2071  bool* pvl = potVertLine;
2072 
2073  for (col = 0; col < bmh.biWidth; col++)
2074  {
2075  *pvl = true;
2076  for (row = 0; ((row < bmh.biHeight) && (*pvl)); row++)
2077  {
2078  if (image[row][col] == 7)
2079  *pvl = false;
2080  }
2081 
2082  pvl++;
2083  }
2084 
2085 
2086  col = 0;
2087 
2088  while (col < bmh.biWidth)
2089  {
2090  if (potVertLine[col])
2091  {
2092  kkint32 firstCol = col;
2093  kkint32 lastCol = col;
2094 
2095  if (col < (bmh.biWidth - 1))
2096  {
2097  while ((col < bmh.biWidth) && (potVertLine[col]))
2098  {
2099  col++;
2100  }
2101  }
2102 
2103  if (!potVertLine[col])
2104  {
2105  // We terminated loop because there were no more potentialVertLine's not
2106  // because we ran out of columns.
2107  lastCol = col - 1;
2108  }
2109 
2110  // Scan down vertically, and any place that we are not in contact both left and right
2111  // with other pixels erase from picture,
2112 
2113 
2114  bool leftSideIsClear = true;
2115  bool rightSizeIsClear = true;
2116 
2117  uchar leftPixel = 0;
2118  uchar rightPixel = 0;
2119 
2120  for (row = 0; row < bmh.biHeight; row++)
2121  {
2122  if (firstCol > 0)
2123  {
2124  leftPixel = image[row][firstCol - 1];
2125  if (leftPixel != 0)
2126  leftSideIsClear = false;
2127  }
2128  else
2129  {
2130  leftPixel = 0;
2131  }
2132 
2133  if (lastCol < (bmh.biWidth - 1))
2134  {
2135  rightPixel = image[row][lastCol + 1];
2136 
2137  if (rightPixel != 0)
2138  rightSizeIsClear = false;
2139  }
2140 
2141  if (leftSideIsClear && rightSizeIsClear)
2142  {
2143  for (x = firstCol; x <= lastCol; x++)
2144  image[row][x] = 0;
2145  }
2146  else
2147  {
2148  for (x = firstCol; x <= lastCol; x++)
2149  image[row][x] = (leftPixel + rightPixel) / 2;
2150 
2151  // Set up boolean for next loop around.
2152  leftSideIsClear = true;
2153  rightSizeIsClear = true;
2154  }
2155  }
2156  }
2157 
2158  col++;
2159  }
2160 
2161  delete[] potVertLine;
2162 } /* EliminateVerticalLines */
2163 
2164 
2165 
2166 
2167 
2168 void BmpImage::Print ()
2169 {
2170  kkint32 x;
2171  kkint32 y;
2172 
2173  for (x = 0; x < bmh.biHeight; x++)
2174  {
2175  for (y = 0; y < Min ((long)bmh.biWidth, 76L); y++)
2176  {
2177  if (image[x][y])
2178  cout << " ";
2179  else
2180  cout << "*";
2181  }
2182 
2183  cout << std::endl;
2184  }
2185 } /* Print */
2186 
2187 
2188 
2190 {
2191  kkint32 row;
2192  kkint32 col;
2193 
2194  for (row = 0; row < bmh.biHeight; row++)
2195  {
2196  for (col = 0; col < bmh.biWidth; col++)
2197  {
2198  if (image[row][col] < 7)
2199  image[row][col] = 0;
2200  }
2201  }
2202 } /* Binarize */
2203 
2204 
2205 
2206 
2207 void BmpImage::SaveGrayscaleInverted4Bit (const KKStr& _fileName)
2208 {
2209  fileName = _fileName;
2210  FILE* outFile = osFOPEN (fileName.Str (), "wb");
2211  if (!outFile)
2212  {
2213  KKStr errMsg = "BmpImage::SaveGrayscaleInverted4Bit, Error opening BMP File[" + fileName + "].";
2214  cerr << errMsg << std::endl;
2215  throw KKException (errMsg);
2216  }
2217 
2218  kkint32 x = 0;
2219  kkint32 y = 0;
2220 
2221  CodedPixels pixelData (bmh.biHeight, bmh.biWidth);
2222 
2223  for (x = (kkint32)bmh.biHeight - 1; x >= 0; x--)
2224  {
2225  for (y = 0; y < bmh.biWidth; y++)
2226  {
2227  if (color)
2228  {
2229  kkint32 gsVal = (kkint32)((float)(0.5f + red[x][y]) * 0.30f + (float)(image[x][y]) * 0.59f + (float)(blue[x][y]) * 0.11f);
2230  pixelData.AddPixel ((uchar)(gsVal >> 4));
2231  }
2232  else
2233  {
2234  pixelData.AddPixel (image[x][y] >> 4);
2235  }
2236  }
2237 
2238  pixelData.EOL ();
2239  }
2240 
2241  kkint32 imageBuffLen = 0;
2242  uchar* imageBuff = NULL;
2243 
2244  numOfColors = 16;
2245  imageBuff = pixelData.CreatePixelDataStructure4Bit (imageBuffLen);
2246  bmh.biBitCount = 4;
2247  bmh.biCompression = BI_RLE4; // BI_RGB;
2248  SetUp4BitPallet ();
2249 
2250  bmh.biSizeImage = imageBuffLen;
2251  bmh.biClrUsed = numOfColors;
2252  bmh.biClrImportant = numOfColors;
2253 
2254  hdr.bfSize = 14 + 40 + paletteEntries * 4 + bmh.biSizeImage;
2255  hdr.bfOffBits = 40 + 14 + paletteEntries * 4;
2256 
2257  x = (kkint32)fwrite (&hdr, sizeof (hdr), 1, outFile);
2258  x = (kkint32)fwrite (&bmh, sizeof (bmh), 1, outFile);
2259  x = (kkint32)fwrite (palette, sizeof (RGBQUAD), paletteEntries, outFile);
2260  x = (kkint32)fwrite (imageBuff, 1, imageBuffLen, outFile);
2261 
2262  delete imageBuff;
2263  fclose (outFile);
2264 } /* SaveGrayscaleInverted4Bit */
2265 
2266 
2267 
2268 void BmpImage::SaveGrayscaleInverted8Bit (const KKStr& _fileName)
2269 {
2270  fileName = _fileName;
2271  FILE* outFile = osFOPEN (fileName.Str (), "wb");
2272  if (!outFile)
2273  {
2274  KKStr errMsg = "BmpImage::SaveGrayscaleInverted8Bit, Error opening BMP File[" + fileName + "].";
2275  cerr << errMsg << std::endl;
2276  throw KKException (errMsg);
2277  }
2278 
2279  kkint32 x = 0;
2280  kkint32 y = 0;
2281 
2282  CodedPixels pixelData (bmh.biHeight, bmh.biWidth);
2283 
2284  for (x = (kkint32)bmh.biHeight - 1; x >= 0; x--)
2285  {
2286  for (y = 0; y < bmh.biWidth; y++)
2287  {
2288  if (color)
2289  {
2290  kkint32 gsVal = (kkint32)((float)(0.5f + red[x][y]) * 0.30f + (float)(image[x][y]) * 0.59f + (float)(blue[x][y]) * 0.11f);
2291  pixelData.AddPixel ((uchar)(gsVal));
2292  }
2293  else
2294  {
2295  pixelData.AddPixel (image[x][y]);
2296  }
2297  }
2298 
2299  pixelData.EOL ();
2300  }
2301 
2302  kkint32 imageBuffLen = 0;
2303  uchar* imageBuff = NULL;
2304 
2305  numOfColors = 256;
2306  imageBuff = pixelData.CreatePixelDataStructure8Bit (imageBuffLen);
2307  bmh.biBitCount = 8;
2308  bmh.biCompression = BI_RLE8; // BI_RGB;
2309  SetUp8BitPallet ();
2310 
2311  bmh.biSizeImage = imageBuffLen;
2312  bmh.biClrUsed = numOfColors;
2313  bmh.biClrImportant = numOfColors;
2314 
2315  hdr.bfSize = 14 + 40 + paletteEntries * 4 + bmh.biSizeImage;
2316  hdr.bfOffBits = 40 + 14 + paletteEntries * 4;
2317 
2318  x = (kkint32)fwrite (&hdr, sizeof (hdr), 1, outFile);
2319  x = (kkint32)fwrite (&bmh, sizeof (bmh), 1, outFile);
2320  x = (kkint32)fwrite (palette, sizeof (RGBQUAD), paletteEntries, outFile);
2321  x = (kkint32)fwrite (imageBuff, 1, imageBuffLen, outFile);
2322 
2323  delete imageBuff;
2324  fclose (outFile);
2325 } /* SaveGrayscaleInverted8Bit */
2326 
2327 
2328 
2329 
2330 
2331 void BmpImage::Save (const KKStr& _fileName)
2332 {
2333  fileName = _fileName;
2334  FILE* outFile = osFOPEN (fileName.Str (), "wb");
2335  if (!outFile)
2336  {
2337  KKStr errMsg = "BmpImage::Save, Error opening BMP File[" + fileName + "].";
2338  cerr << errMsg << std::endl;
2339  throw KKException (errMsg);
2340  }
2341 
2342  if (color)
2343  {
2344  SaveColor (outFile);
2345  }
2346  else
2347  {
2348  SaveGrayScale (outFile);
2349  }
2350 
2351  fclose (outFile);
2352 } /* Save */
2353 
2354 
2355 
2356 
2357 void BmpImage::SaveGrayScale (FILE* outFile)
2358 {
2359  kkint32 x;
2360  kkint32 y;
2361 
2362  CodedPixels pixelData (bmh.biHeight, bmh.biWidth);
2363 
2364  for (x = (kkint32)bmh.biHeight - 1; x >= 0; x--)
2365  {
2366  for (y = 0; y < bmh.biWidth; y++)
2367  {
2368  pixelData.AddPixel (image[x][y]);
2369  }
2370 
2371  pixelData.EOL ();
2372  }
2373 
2374  kkint32 imageBuffLen;
2375  uchar* imageBuff;
2376 
2377  numOfColors = 256;
2378  imageBuff = pixelData.CreatePixelDataStructure8Bit (imageBuffLen);
2379  bmh.biCompression = BI_RLE8;
2380  bmh.biBitCount = 8;
2381 
2382  bmh.biSizeImage = imageBuffLen;
2383  bmh.biClrUsed = numOfColors;
2384  bmh.biClrImportant = numOfColors;
2385  paletteEntries = numOfColors;
2386 
2387  hdr.bfSize = 14 + 40 + paletteEntries * 4 + bmh.biSizeImage;
2388  hdr.bfOffBits = 40 + 14 + paletteEntries * 4;
2389 
2390  #ifndef WIN32
2391  WriteWORD (outFile, hdr.bfType);
2392  WriteDWORD (outFile, hdr.bfSize);
2393  WriteWORD (outFile, hdr.bfReserved1);
2394  WriteWORD (outFile, hdr.bfReserved2);
2395  WriteDWORD (outFile, hdr.bfOffBits);
2396  #else
2397 
2398  x = (kkint32)fwrite (&hdr, sizeof (hdr), 1, outFile);
2399  #endif
2400 
2401 
2402  #ifndef WIN32
2403  WriteDWORD (outFile, bmh.biSize);
2404  WriteLONG (outFile, bmh.biWidth);
2405  WriteLONG (outFile, bmh.biHeight);
2406  WriteWORD (outFile, bmh.biPlanes);
2407  WriteWORD (outFile, bmh.biBitCount);
2408  WriteDWORD (outFile, bmh.biCompression);
2409  WriteDWORD (outFile, bmh.biSizeImage);
2410  WriteLONG (outFile, bmh.biXPelsPerMeter);
2411  WriteLONG (outFile, bmh.biYPelsPerMeter);
2412  WriteDWORD (outFile, bmh.biClrUsed);
2413  WriteDWORD (outFile, bmh.biClrImportant);
2414  #else
2415 
2416  x = (kkint32)fwrite (&bmh, sizeof (bmh), 1, outFile);
2417  #endif
2418 
2419 
2420  #ifndef WIN32
2421  for (x = 0; x < paletteEntries; x++)
2422  {
2423  WriteBYTE (outFile, palette[x].rgbBlue);
2424  WriteBYTE (outFile, palette[x].rgbGreen);
2425  WriteBYTE (outFile, palette[x].rgbRed);
2426  WriteBYTE (outFile, palette[x].rgbReserved);
2427  }
2428  #else
2429  x = (kkint32)fwrite (palette, sizeof (RGBQUAD), paletteEntries, outFile);
2430  #endif
2431 
2432  x = (kkint32)fwrite (imageBuff, 1, imageBuffLen, outFile);
2433  delete imageBuff;
2434 } /* SaveGrayScale */
2435 
2436 
2437 
2438 
2439 void BmpImage::SaveColor (FILE* outFile)
2440 {
2441  /** @todo Need to finish implementing and testing compressed color. */
2442  PalletBuilderPtr palletBuilder = BuildPalletFromRasterData ();
2443  if (palletBuilder->NumOfColors () <= 256)
2444  SaveColorCompressed256 (palletBuilder, outFile);
2445  else
2446  SaveColor24BPP (outFile);
2447  delete palletBuilder;
2448  palletBuilder = NULL;
2449 
2450 
2451  //SaveColor24BPP (outFile);
2452 } /* SaveColor */
2453 
2454 
2455 /** @brief Will write a color compressed BMP file with a maximum of 256 colors. */
2456 void BmpImage::SaveColorCompressed256 (PalletBuilderPtr palletBuilder,
2457  FILE* outFile
2458  )
2459 {
2460  kkint32 x;
2461  kkint32 y;
2462 
2463  uchar* redRow = NULL;
2464  uchar* greenRow = NULL;
2465  uchar* blueRow = NULL;
2466 
2467  kkint32 palletIdx = 0;
2468 
2469  CodedPixels pixelData (bmh.biHeight, bmh.biWidth);
2470 
2471  for (x = (kkint32)bmh.biHeight - 1; x >= 0; x--)
2472  {
2473  redRow = red[x];
2474  greenRow = image[x];
2475  blueRow = blue[x];
2476  for (y = 0; y < bmh.biWidth; y++)
2477  {
2478  palletIdx = palletBuilder->PalletIndex (redRow[y], greenRow[y], blueRow[y]);
2479 
2480  if (palletIdx < 0)
2481  palletIdx = 0;
2482 
2483  else if (palletIdx > 255)
2484  palletIdx = 255;
2485 
2486  pixelData.AddPixel ((uchar)palletIdx);
2487  }
2488 
2489  pixelData.EOL ();
2490  }
2491 
2492  kkint32 imageBuffLen;
2493  uchar* imageBuff;
2494 
2495  numOfColors = paletteEntries;
2496  imageBuff = pixelData.CreatePixelDataStructure8Bit (imageBuffLen);
2497  bmh.biCompression = BI_RLE8; /* 'BI_RLE8' is where each pixel is represented by a 8 bit number that indexes into a color palette. */
2498  bmh.biBitCount = 8;
2499 
2500  bmh.biSizeImage = imageBuffLen;
2501  bmh.biClrUsed = numOfColors;
2502  bmh.biClrImportant = numOfColors;
2503 
2504  hdr.bfSize = 14 + 40 + paletteEntries * 4 + bmh.biSizeImage;
2505  hdr.bfOffBits = 40 + 14 + paletteEntries * 4;
2506 
2507  #ifndef WIN32
2508  WriteWORD (outFile, hdr.bfType);
2509  WriteDWORD (outFile, hdr.bfSize);
2510  WriteWORD (outFile, hdr.bfReserved1);
2511  WriteWORD (outFile, hdr.bfReserved2);
2512  WriteDWORD (outFile, hdr.bfOffBits);
2513  #else
2514 
2515  x = (kkint32)fwrite (&hdr, sizeof (hdr), 1, outFile);
2516  #endif
2517 
2518 
2519  #ifndef WIN32
2520  WriteDWORD (outFile, bmh.biSize);
2521  WriteLONG (outFile, bmh.biWidth);
2522  WriteLONG (outFile, bmh.biHeight);
2523  WriteWORD (outFile, bmh.biPlanes);
2524  WriteWORD (outFile, bmh.biBitCount);
2525  WriteDWORD (outFile, bmh.biCompression);
2526  WriteDWORD (outFile, bmh.biSizeImage);
2527  WriteLONG (outFile, bmh.biXPelsPerMeter);
2528  WriteLONG (outFile, bmh.biYPelsPerMeter);
2529  WriteDWORD (outFile, bmh.biClrUsed);
2530  WriteDWORD (outFile, bmh.biClrImportant);
2531  #else
2532 
2533  x = (kkint32)fwrite (&bmh, sizeof (bmh), 1, outFile);
2534  #endif
2535 
2536 
2537  #ifndef WIN32
2538  for (x = 0; x < paletteEntries; x++)
2539  {
2540  WriteBYTE (outFile, palette[x].rgbBlue);
2541  WriteBYTE (outFile, palette[x].rgbGreen);
2542  WriteBYTE (outFile, palette[x].rgbRed);
2543  WriteBYTE (outFile, palette[x].rgbReserved);
2544  }
2545  #else
2546  x = (kkint32)fwrite (palette, sizeof (RGBQUAD), paletteEntries, outFile);
2547  #endif
2548 
2549 
2550  x = (kkint32)fwrite (imageBuff, 1, imageBuffLen, outFile);
2551  delete imageBuff;
2552 } /* SaveColorCompressed256 */
2553 
2554 
2555 
2556 void BmpImage::SaveColor24BPP (FILE* outFile)
2557 {
2558  kkint32 x = 0;
2559  kkint32 bytesPerRow = Width () * 3;
2560  kkint32 bufferPerRow = 0;
2561  while ((bytesPerRow % 4) != 0)
2562  {
2563  bufferPerRow++;
2564  bytesPerRow++;
2565  }
2566 
2567  bmh.biSize = 40;
2568  //bmh.biWidth = Width ();
2569  //bmh.biHeight = height ();
2570  bmh.biPlanes = 1;
2571  bmh.biBitCount = 24;
2572  bmh.biCompression = BI_RGB;
2573  bmh.biSizeImage = Height () * bytesPerRow;
2574  bmh.biXPelsPerMeter = 2835;
2575  bmh.biYPelsPerMeter = 2835;
2576  bmh.biClrUsed = 0;
2577  bmh.biClrImportant = 0;
2578 
2579  hdr.bfSize = 14 + 40 + 0 * 4 + bmh.biSizeImage;
2580  hdr.bfOffBits = 40 + 14 + 0 * 4;
2581 
2582  #ifndef WIN32
2583  WriteWORD (outFile, hdr.bfType);
2584  WriteDWORD (outFile, hdr.bfSize);
2585  WriteWORD (outFile, hdr.bfReserved1);
2586  WriteWORD (outFile, hdr.bfReserved2);
2587  WriteDWORD (outFile, hdr.bfOffBits);
2588  #else
2589  x = (kkint32)fwrite (&hdr, sizeof (hdr), 1, outFile);
2590  #endif
2591 
2592 
2593  #ifndef WIN32
2594  WriteDWORD (outFile, bmh.biSize);
2595  WriteLONG (outFile, bmh.biWidth);
2596  WriteLONG (outFile, bmh.biHeight);
2597  WriteWORD (outFile, bmh.biPlanes);
2598  WriteWORD (outFile, bmh.biBitCount);
2599  WriteDWORD (outFile, bmh.biCompression);
2600  WriteDWORD (outFile, bmh.biSizeImage);
2601  WriteLONG (outFile, bmh.biXPelsPerMeter);
2602  WriteLONG (outFile, bmh.biYPelsPerMeter);
2603  WriteDWORD (outFile, bmh.biClrUsed);
2604  WriteDWORD (outFile, bmh.biClrImportant);
2605  #else
2606 
2607  x = (kkint32)fwrite (&bmh, sizeof (bmh), 1, outFile);
2608  #endif
2609 
2610 
2611  kkint32 row, col;
2612  for (row = (kkint32)Height () - 1; row >= 0; row--)
2613  {
2614  for (col = 0; col < (kkint32)Width (); col++)
2615  {
2616  fwrite (&(blue [row][col]), 1, 1, outFile);
2617  fwrite (&(image[row][col]), 1, 1, outFile);
2618  fwrite (&(red [row][col]), 1, 1, outFile);
2619  }
2620 
2621  uchar pad = 0;
2622  for (x = 0; x < bufferPerRow; x++)
2623  fwrite (&pad, 1, 1, outFile);
2624  }
2625 } /* SaveColor24BPP */
2626 
2627 
2628 
2629 
2631  kkuint32 col,
2632  uchar pixValue
2633  )
2634 {
2635  image[row][col] = pixValue;
2636 }
2637 
2638 
2639 
2641 {
2642  kkint32 row;
2643  for (row = 0; row < bmh.biHeight; row++)
2644  {
2645  memset (image[row], 0, bmh.biWidth );
2646  }
2647 }
2648 
2649 
2650 
2651 const
2653 {
2654  if (blue == NULL)
2655  throw KKException("BmpImage::BlueRow 'blue' channel is set to NULL.");
2656  if ((row < 0) || (row >= (kkint32)Height ()))
2657  {
2658  cerr << std::endl
2659  << std::endl
2660  << "BmpImage::BlueRow *** ERROR *** Invalid Row[" << row << "]." << std::endl
2661  << std::endl;
2662  //osWaitForEnter ();
2663  throw KKException("BmpImage::BlueRow row:" + StrFromInt32(row) + " is out of range where Height:" + StrFromInt32(row));
2664  }
2665 
2666  return blue[row];
2667 } /* BlueRow */
2668 
2669 
2670 
2671 const
2673 {
2674  if (image == NULL)
2675  throw KKException("::ImageRow 'image' set to NULL.");
2676  if ((row < 0) || (row >= (kkint32)Height ()))
2677  {
2678  cerr << std::endl
2679  << std::endl
2680  << "BmpImage *** ERROR *** Invalid Row[" << row << "]." << std::endl
2681  << std::endl;
2682  throw KKException("BmpImage::ImageRow row:" + StrFromInt32(row) + " is out of range where Height:" + StrFromInt32(row));
2683  }
2684 
2685  return image[row];
2686 } /* ImageRow */
2687 
2688 
2689 const
2691 {
2692  if (blue == NULL)
2693  throw KKException("BmpImage::RedRow 'red' channel is set to NULL.");
2694  if ((row < 0) || (row >= (kkint32)Height()))
2695  {
2696  cerr << std::endl
2697  << std::endl
2698  << "BmpImage::RedRow *** ERROR *** Invalid Row[" << row << "]." << std::endl
2699  << std::endl;
2700  //osWaitForEnter ();
2701  throw KKException("BmpImage::BlueRed row:" + StrFromInt32(row) + " is out of range where Height:" + StrFromInt32(row));
2702  }
2703 
2704  return red[row];
2705 } /* RedRow */
2706 
2707 
2708 
2710 {
2711  return ((bmh.biBitCount == 4) && (bmh.biCompression == BI_RGB));
2712 }
__int32 kkint32
Definition: KKBaseTypes.h:88
bool AreThereEdgePixels()
Definition: BMPImage.cpp:2004
kkuint32 Height() const
Definition: BMPImage.h:125
void BuildPallet(RGBQUAD *&palette, kkint32 &size)
Definition: BMPImage.cpp:1135
void Set16Colors()
Definition: BMPImage.cpp:1194
kkint32 NumOfColors() const
Definition: BMPImage.cpp:1092
KKStr & operator=(const char *src)
Definition: KKStr.cpp:1442
void ReAllocateForBiggerScreen()
Used to expand dimensions of image by 6 pixels so as to make sure that no image is along the edge...
Definition: BMPImage.cpp:1318
A class that is used by to represent a single image in memory.
Definition: Raster.h:108
void SaveGrayscaleInverted8Bit(const KKStr &_fileName)
Saves image using compressed gray-scale where Background = 255 and foreground = 0.
Definition: BMPImage.cpp:2268
This object is used to help encode the data stored in BMPImage::image into 8 or 4 bit compressed form...
Definition: BMPImage.cpp:163
CodedPixels(kkint32 _height, kkint32 _width)
Definition: BMPImage.cpp:200
bool Color() const
Definition: Raster.h:310
KKStr operator+(const char *right) const
Definition: KKStr.cpp:3986
uchar ** Red() const
Definition: Raster.h:326
const uchar * RedRow(kkint32 row) const
Returns the specified Row from the Red Channel.
Definition: BMPImage.cpp:2690
unsigned __int32 kkuint32
Definition: KKBaseTypes.h:89
const uchar * ImageRow(kkint32 row) const
Returns the specified Row from the Green Channel.
Definition: BMPImage.cpp:2672
BmpImage(const Raster &raster)
Constructs a BMPImage instance from a Raster image; this is one way to save a Raster image to disk...
Definition: BMPImage.cpp:706
uchar & Pixel(kkint32 row, kkint32 col)
Definition: BMPImage.cpp:1958
void Binarize()
Definition: BMPImage.cpp:2189
kkint32 Height() const
Definition: Raster.h:319
KKTHread * KKTHreadPtr
void DownSize()
Definition: BMPImage.cpp:1917
KKStr operator+(const char *left, const KKStr &right)
Definition: KKStr.cpp:3976
Used to encode and decode BMP Images.
Definition: BMPImage.h:49
BmpImage(kkint32 _height, kkint32 _width, kkint32 _numOfColors)
Definition: BMPImage.cpp:687
void SaveGrayscaleInverted4Bit(const KKStr &_fileName)
Saves image using 4 bit compressed gray-scale where Background = 255 and foreground = 0...
Definition: BMPImage.cpp:2207
KKStr(const KKStr &str)
Copy Constructor.
Definition: KKStr.cpp:561
uchar * CreatePixelDataStructure8Bit(kkint32 &len)
Definition: BMPImage.cpp:358
unsigned char uchar
Unsigned character.
Definition: KKBaseTypes.h:77
static KKStr Concat(const std::vector< std::string > &values)
Concatenates the list of &#39;std::string&#39; strings.
Definition: KKStr.cpp:1082
void AddColor(uchar red, uchar green, uchar blue)
Definition: BMPImage.cpp:1111
void EliminateVerticalLines()
Definition: BMPImage.cpp:2063
bool operator()(const RGBQUAD &left, const RGBQUAD &right) const
Definition: BMPImage.cpp:1072
CodePair * CodePairPtr
Definition: BMPImage.h:214
void Save(const KKStr &fileName)
Definition: BMPImage.cpp:2331
void AddPixel(uchar pixel)
Definition: BMPImage.cpp:223
std::ostream &__cdecl operator<<(std::ostream &os, const KKStr &str)
kkuint32 Width() const
Definition: BMPImage.h:140
KKStr operator+(const KKStr &right) const
Definition: KKStr.cpp:3998
const uchar * BlueRow(kkint32 row) const
Returns the specified Row from the Blue Channel.
Definition: BMPImage.cpp:2652
void SetPaletteEntry(kkint32 palletIndex, const PixelValue &pixValue)
Definition: BMPImage.cpp:935
const char * Str() const
Returns a pointer to a ascii string.
Definition: KKStr.h:422
kkint32 Width() const
Definition: Raster.h:324
FILE * osFOPEN(const char *fileName, const char *mode)
Definition: OSservices.cpp:74
uchar * CreatePixelDataStructure4Bit(kkint32 &len)
Definition: BMPImage.cpp:277
KKException(const char *_exceptionStr)
Definition: KKException.cpp:38
KKStr & operator=(const KKStr &src)
Definition: KKStr.cpp:1390
uchar ** Blue() const
Definition: Raster.h:328
void InitializeFields(kkint32 _height, kkint32 _width)
Definition: BMPImage.cpp:1011
void AddPixel(kkuint32 row, kkuint32 col, uchar pixValue)
Definition: BMPImage.cpp:2630
void SetPixelValue(kkint32 row, kkint32 col, kkint32 pixel)
Will set the pixel value of the specified row and col to &#39;pixel&#39;.
Definition: BMPImage.cpp:1967
KKException(const KKStr &_exceptionStr)
Definition: KKException.cpp:45
bool FourBitUncompressed()
Definition: BMPImage.cpp:2709
BmpImage(const KKStr &_fileName, bool &successful)
Constructs a BMP image from the file specified by &#39;_fileName&#39;.
Definition: BMPImage.cpp:449
bool GrayScaleImage(RGBQUAD *palette, kkint32 palletSize)
Returns true if palette is for a grayscale image.
Definition: BMPImage.cpp:988
void Set256Colors()
Definition: BMPImage.cpp:1208
kkint32 PalletIndex(uchar red, uchar green, uchar blue)
Definition: BMPImage.cpp:1094
Used by the Raster Class to represent the contents of one pixel.
Definition: PixelValue.h:22
uchar ** Rows() const
Definition: Raster.h:321
void ClearImage()
Definition: BMPImage.cpp:2640
KKStr StrFromInt32(kkint32 i)
Definition: KKStr.cpp:5175