1 /*************************************************
3 * EasyBMP Cross-Platform Windows Bitmap Library *
5 * Author: Paul Macklin *
6 * email: macklin01@users.sourceforge.net *
7 * support: http://easybmp.sourceforge.net *
10 * date added: 03-31-2006 *
11 * date modified: 12-01-2006 *
14 * License: BSD (revised/modified) *
15 * Copyright: 2005-6 by the EasyBMP Project *
17 * description: Actual source file *
19 *************************************************/
\r
21 #include "../../../../include/freenet/captcha/easybmp/EasyBMP.h"
\r
23 /* These functions are defined in EasyBMP.h */
25 bool EasyBMPwarnings = true;
27 void SetEasyBMPwarningsOff( void )
28 { EasyBMPwarnings = false; }
29 void SetEasyBMPwarningsOn( void )
30 { EasyBMPwarnings = true; }
31 bool GetEasyBMPwarningState( void )
32 { return EasyBMPwarnings; }
34 /* These functions are defined in EasyBMP_DataStructures.h */
\r
36 int IntPow( int base, int exponent )
40 for( i=0 ; i < exponent ; i++ )
52 void BMFH::SwitchEndianess( void )
54 bfType = FlipWORD( bfType );
55 bfSize = FlipDWORD( bfSize );
56 bfReserved1 = FlipWORD( bfReserved1 );
57 bfReserved2 = FlipWORD( bfReserved2 );
58 bfOffBits = FlipDWORD( bfOffBits );
66 biXPelsPerMeter = DefaultXPelsPerMeter;
67 biYPelsPerMeter = DefaultYPelsPerMeter;
72 void BMIH::SwitchEndianess( void )
74 biSize = FlipDWORD( biSize );
75 biWidth = FlipDWORD( biWidth );
76 biHeight = FlipDWORD( biHeight );
77 biPlanes = FlipWORD( biPlanes );
78 biBitCount = FlipWORD( biBitCount );
79 biCompression = FlipDWORD( biCompression );
80 biSizeImage = FlipDWORD( biSizeImage );
81 biXPelsPerMeter = FlipDWORD( biXPelsPerMeter );
82 biYPelsPerMeter = FlipDWORD( biYPelsPerMeter );
83 biClrUsed = FlipDWORD( biClrUsed );
84 biClrImportant = FlipDWORD( biClrImportant );
88 void BMIH::display( void )
91 cout << "biSize: " << (int) biSize << endl
92 << "biWidth: " << (int) biWidth << endl
93 << "biHeight: " << (int) biHeight << endl
94 << "biPlanes: " << (int) biPlanes << endl
95 << "biBitCount: " << (int) biBitCount << endl
96 << "biCompression: " << (int) biCompression << endl
97 << "biSizeImage: " << (int) biSizeImage << endl
98 << "biXPelsPerMeter: " << (int) biXPelsPerMeter << endl
99 << "biYPelsPerMeter: " << (int) biYPelsPerMeter << endl
100 << "biClrUsed: " << (int) biClrUsed << endl
101 << "biClrImportant: " << (int) biClrImportant << endl << endl;
104 void BMFH::display( void )
107 cout << "bfType: " << (int) bfType << endl
108 << "bfSize: " << (int) bfSize << endl
109 << "bfReserved1: " << (int) bfReserved1 << endl
110 << "bfReserved2: " << (int) bfReserved2 << endl
111 << "bfOffBits: " << (int) bfOffBits << endl << endl;
114 /* These functions are defined in EasyBMP_BMP.h */
116 RGBApixel BMP::GetPixel( int i, int j ) const
121 { i = Width-1; Warn = true; }
123 { i = 0; Warn = true; }
125 { j = Height-1; Warn = true; }
127 { j = 0; Warn = true; }
128 if( Warn && EasyBMPwarnings )
130 cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
131 << " Truncating request to fit in the range [0,"
132 << Width-1 << "] x [0," << Height-1 << "]." << endl;
137 bool BMP::SetPixel( int i, int j, RGBApixel NewPixel )
139 Pixels[i][j] = NewPixel;
144 bool BMP::SetColor( int ColorNumber , RGBApixel NewColor )
147 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
149 if( EasyBMPwarnings )
151 cout << "EasyBMP Warning: Attempted to change color table for a BMP object" << endl
152 << " that lacks a color table. Ignoring request." << endl;
158 if( EasyBMPwarnings )
160 cout << "EasyBMP Warning: Attempted to set a color, but the color table" << endl
161 << " is not defined. Ignoring request." << endl;
165 if( ColorNumber >= TellNumberOfColors() )
167 if( EasyBMPwarnings )
169 cout << "EasyBMP Warning: Requested color number "
170 << ColorNumber << " is outside the allowed" << endl
171 << " range [0," << TellNumberOfColors()-1
172 << "]. Ignoring request to set this color." << endl;
176 Colors[ColorNumber] = NewColor;
180 // RGBApixel BMP::GetColor( int ColorNumber ) const
181 RGBApixel BMP::GetColor( int ColorNumber )
190 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
192 if( EasyBMPwarnings )
194 cout << "EasyBMP Warning: Attempted to access color table for a BMP object" << endl
195 << " that lacks a color table. Ignoring request." << endl;
201 if( EasyBMPwarnings )
203 cout << "EasyBMP Warning: Requested a color, but the color table" << endl
204 << " is not defined. Ignoring request." << endl;
208 if( ColorNumber >= TellNumberOfColors() )
210 if( EasyBMPwarnings )
212 cout << "EasyBMP Warning: Requested color number "
213 << ColorNumber << " is outside the allowed" << endl
214 << " range [0," << TellNumberOfColors()-1
215 << "]. Ignoring request to get this color." << endl;
219 Output = Colors[ColorNumber];
228 Pixels = new RGBApixel* [Width];
229 Pixels[0] = new RGBApixel [Height];
241 // BMP::BMP( const BMP& Input )
242 BMP::BMP( BMP& Input )
244 // first, make the image empty.
249 Pixels = new RGBApixel* [Width];
250 Pixels[0] = new RGBApixel [Height];
260 // now, set the correct bit depth
262 SetBitDepth( Input.TellBitDepth() );
264 // set the correct pixel size
266 SetSize( Input.TellWidth() , Input.TellHeight() );
268 // set the DPI information from Input
270 SetDPI( Input.TellHorizontalDPI() , Input.TellVerticalDPI() );
272 // if there is a color table, get all the colors
274 if( BitDepth == 1 || BitDepth == 4 ||
277 for( int k=0 ; k < TellNumberOfColors() ; k++ )
279 SetColor( k, Input.GetColor( k ));
283 // get all the pixels
285 for( int j=0; j < Height ; j++ )
287 for( int i=0; i < Width ; i++ )
289 Pixels[i][j] = *Input(i,j);
290 // Pixels[i][j] = Input.GetPixel(i,j); // *Input(i,j);
299 { delete [] Pixels[i]; }
302 { delete [] Colors; }
305 { delete [] MetaData1; }
307 { delete [] MetaData2; }
310 RGBApixel* BMP::operator()(int i, int j)
315 { i = Width-1; Warn = true; }
317 { i = 0; Warn = true; }
319 { j = Height-1; Warn = true; }
321 { j = 0; Warn = true; }
322 if( Warn && EasyBMPwarnings )
324 cout << "EasyBMP Warning: Attempted to access non-existent pixel;" << endl
325 << " Truncating request to fit in the range [0,"
326 << Width-1 << "] x [0," << Height-1 << "]." << endl;
328 return &(Pixels[i][j]);
331 // int BMP::TellBitDepth( void ) const
332 int BMP::TellBitDepth( void )
335 // int BMP::TellHeight( void ) const
336 int BMP::TellHeight( void )
339 // int BMP::TellWidth( void ) const
340 int BMP::TellWidth( void )
343 // int BMP::TellNumberOfColors( void ) const
344 int BMP::TellNumberOfColors( void )
346 int output = IntPow( 2, BitDepth );
348 { output = IntPow( 2, 24 ); }
352 bool BMP::SetBitDepth( int NewDepth )
355 if( NewDepth != 1 && NewDepth != 4 &&
356 NewDepth != 8 && NewDepth != 16 &&
357 NewDepth != 24 && NewDepth != 32 )
359 if( EasyBMPwarnings )
361 cout << "EasyBMP Warning: User attempted to set unsupported bit depth "
362 << NewDepth << "." << endl
363 << " Bit depth remains unchanged at "
364 << BitDepth << "." << endl;
371 { delete [] Colors; }
372 int NumberOfColors = IntPow( 2, BitDepth );
373 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
374 { Colors = new RGBApixel [NumberOfColors]; }
377 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
378 { CreateStandardColorTable(); }
383 bool BMP::SetSize(int NewWidth , int NewHeight )
386 if( NewWidth <= 0 || NewHeight <= 0 )
388 if( EasyBMPwarnings )
390 cout << "EasyBMP Warning: User attempted to set a non-positive width or height." << endl
391 << " Size remains unchanged at "
392 << Width << " x " << Height << "." << endl;
400 { delete [] Pixels[i]; }
405 Pixels = new RGBApixel* [ Width ];
407 for(i=0; i<Width; i++)
408 { Pixels[i] = new RGBApixel [ Height ]; }
410 for( i=0 ; i < Width ; i++)
412 for( j=0 ; j < Height ; j++ )
414 Pixels[i][j].Red = 255;
415 Pixels[i][j].Green = 255;
416 Pixels[i][j].Blue = 255;
417 Pixels[i][j].Alpha = 0;
424 bool BMP::WriteToFile( const char* FileName )
427 if( !EasyBMPcheckDataSize() )
429 if( EasyBMPwarnings )
431 cout << "EasyBMP Error: Data types are wrong size!" << endl
432 << " You may need to mess with EasyBMP_DataTypes.h" << endl
433 << " to fix these errors, and then recompile." << endl
434 << " All 32-bit and 64-bit machines should be" << endl
435 << " supported, however." << endl << endl;
440 FILE* fp = fopen( FileName, "wb" );
443 if( EasyBMPwarnings )
445 cout << "EasyBMP Error: Cannot open file "
446 << FileName << " for output." << endl;
452 // some preliminaries
454 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
455 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
456 dBytesPerRow = ceil(dBytesPerRow);
458 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
459 if( BytePaddingPerRow == 4 )
460 { BytePaddingPerRow = 0; }
462 double dActualBytesPerRow = dBytesPerRow + BytePaddingPerRow;
464 double dTotalPixelBytes = Height * dActualBytesPerRow;
466 double dPaletteSize = 0;
467 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
468 { dPaletteSize = IntPow(2,BitDepth)*4.0; }
470 // leave some room for 16-bit masks
472 { dPaletteSize = 3*4; }
474 double dTotalFileSize = 14 + 40 + dPaletteSize + dTotalPixelBytes;
476 // write the file header
479 bmfh.bfSize = (ebmpDWORD) dTotalFileSize;
480 bmfh.bfReserved1 = 0;
481 bmfh.bfReserved2 = 0;
482 bmfh.bfOffBits = (ebmpDWORD) (14+40+dPaletteSize);
485 { bmfh.SwitchEndianess(); }
487 fwrite( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
488 fwrite( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
489 fwrite( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
490 fwrite( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
491 fwrite( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
493 // write the info header
497 bmih.biWidth = Width;
498 bmih.biHeight = Height;
500 bmih.biBitCount = BitDepth;
501 bmih.biCompression = 0;
502 bmih.biSizeImage = (ebmpDWORD) dTotalPixelBytes;
504 { bmih.biXPelsPerMeter = XPelsPerMeter; }
506 { bmih.biXPelsPerMeter = DefaultXPelsPerMeter; }
508 { bmih.biYPelsPerMeter = YPelsPerMeter; }
510 { bmih.biYPelsPerMeter = DefaultYPelsPerMeter; }
513 bmih.biClrImportant = 0;
515 // indicates that we'll be using bit fields for 16-bit files
517 { bmih.biCompression = 3; }
520 { bmih.SwitchEndianess(); }
522 fwrite( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
523 fwrite( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
524 fwrite( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
525 fwrite( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
526 fwrite( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
527 fwrite( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
528 fwrite( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
529 fwrite( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
530 fwrite( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
531 fwrite( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
532 fwrite( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
535 if( BitDepth == 1 || BitDepth == 4 || BitDepth == 8 )
537 int NumberOfColors = IntPow(2,BitDepth);
539 // if there is no palette, create one
543 { Colors = new RGBApixel [NumberOfColors]; }
544 CreateStandardColorTable();
548 for( n=0 ; n < NumberOfColors ; n++ )
549 { fwrite( (char*) &(Colors[n]) , 4 , 1 , fp ); }
557 int BufferSize = (int) ( (Width*BitDepth)/8.0 );
558 while( 8*BufferSize < Width*BitDepth )
560 while( BufferSize % 4 )
563 Buffer = new ebmpBYTE [BufferSize];
564 for( j=0 ; j < BufferSize; j++ )
571 bool Success = false;
573 { Success = Write32bitRow( Buffer, BufferSize, j ); }
575 { Success = Write24bitRow( Buffer, BufferSize, j ); }
577 { Success = Write8bitRow( Buffer, BufferSize, j ); }
579 { Success = Write4bitRow( Buffer, BufferSize, j ); }
581 { Success = Write1bitRow( Buffer, BufferSize, j ); }
584 int BytesWritten = (int) fwrite( (char*) Buffer, 1, BufferSize, fp );
585 if( BytesWritten != BufferSize )
590 if( EasyBMPwarnings )
592 cout << "EasyBMP Error: Could not write proper amount of data." << endl;
604 // write the bit masks
606 ebmpWORD BlueMask = 31; // bits 12-16
607 ebmpWORD GreenMask = 2016; // bits 6-11
608 ebmpWORD RedMask = 63488; // bits 1-5
612 { RedMask = FlipWORD( RedMask ); }
613 fwrite( (char*) &RedMask , 2 , 1 , fp );
614 fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
617 { GreenMask = FlipWORD( GreenMask ); }
618 fwrite( (char*) &GreenMask , 2 , 1 , fp );
619 fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
622 { BlueMask = FlipWORD( BlueMask ); }
623 fwrite( (char*) &BlueMask , 2 , 1 , fp );
624 fwrite( (char*) &ZeroWORD , 2 , 1 , fp );
626 int DataBytes = Width*2;
627 int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
629 // write the actual pixels
631 for( j=Height-1 ; j >= 0 ; j-- )
633 // write all row pixel data
636 while( WriteNumber < DataBytes )
640 ebmpWORD RedWORD = (ebmpWORD) ((Pixels[i][j]).Red / 8);
641 ebmpWORD GreenWORD = (ebmpWORD) ((Pixels[i][j]).Green / 4);
642 ebmpWORD BlueWORD = (ebmpWORD) ((Pixels[i][j]).Blue / 8);
644 TempWORD = (RedWORD<<11) + (GreenWORD<<5) + BlueWORD;
646 { TempWORD = FlipWORD( TempWORD ); }
648 fwrite( (char*) &TempWORD , 2, 1, fp);
652 // write any necessary row padding
654 while( WriteNumber < PaddingBytes )
657 fwrite( (char*) &TempBYTE , 1, 1, fp);
668 bool BMP::ReadFromFile( const char* FileName )
671 if( !EasyBMPcheckDataSize() )
673 if( EasyBMPwarnings )
675 cout << "EasyBMP Error: Data types are wrong size!" << endl
676 << " You may need to mess with EasyBMP_DataTypes.h" << endl
677 << " to fix these errors, and then recompile." << endl
678 << " All 32-bit and 64-bit machines should be" << endl
679 << " supported, however." << endl << endl;
684 FILE* fp = fopen( FileName, "rb" );
687 if( EasyBMPwarnings )
689 cout << "EasyBMP Error: Cannot open file "
690 << FileName << " for input." << endl;
697 // read the file header
700 bool NotCorrupted = true;
702 NotCorrupted &= SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD), 1, fp);
704 bool IsBitmap = false;
706 if( IsBigEndian() && bmfh.bfType == 16973 )
708 if( !IsBigEndian() && bmfh.bfType == 19778 )
713 if( EasyBMPwarnings )
715 cout << "EasyBMP Error: " << FileName
716 << " is not a Windows BMP file!" << endl;
722 NotCorrupted &= SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1, fp);
723 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1, fp);
724 NotCorrupted &= SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1, fp);
725 NotCorrupted &= SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp);
728 { bmfh.SwitchEndianess(); }
730 // read the info header
734 NotCorrupted &= SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp);
735 NotCorrupted &= SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp);
736 NotCorrupted &= SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp);
737 NotCorrupted &= SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1, fp);
738 NotCorrupted &= SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1, fp);
740 NotCorrupted &= SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp);
741 NotCorrupted &= SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp);
742 NotCorrupted &= SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
743 NotCorrupted &= SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp);
744 NotCorrupted &= SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp);
745 NotCorrupted &= SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp);
748 { bmih.SwitchEndianess(); }
750 // a safety catch: if any of the header information didn't read properly, abort
751 // future idea: check to see if at least most is self-consistent
755 if( EasyBMPwarnings )
757 cout << "EasyBMP Error: " << FileName
758 << " is obviously corrupted." << endl;
766 XPelsPerMeter = bmih.biXPelsPerMeter;
767 YPelsPerMeter = bmih.biYPelsPerMeter;
769 // if bmih.biCompression 1 or 2, then the file is RLE compressed
771 if( bmih.biCompression == 1 || bmih.biCompression == 2 )
773 if( EasyBMPwarnings )
775 cout << "EasyBMP Error: " << FileName << " is (RLE) compressed." << endl
776 << " EasyBMP does not support compression." << endl;
784 // if bmih.biCompression > 3, then something strange is going on
785 // it's probably an OS2 bitmap file.
787 if( bmih.biCompression > 3 )
789 if( EasyBMPwarnings )
791 cout << "EasyBMP Error: " << FileName << " is in an unsupported format."
793 << " (bmih.biCompression = "
794 << bmih.biCompression << ")" << endl
795 << " The file is probably an old OS2 bitmap or corrupted."
804 if( bmih.biCompression == 3 && bmih.biBitCount != 16 )
806 if( EasyBMPwarnings )
808 cout << "EasyBMP Error: " << FileName
809 << " uses bit fields and is not a" << endl
810 << " 16-bit file. This is not supported." << endl;
820 int TempBitDepth = (int) bmih.biBitCount;
821 if( TempBitDepth != 1 && TempBitDepth != 4
822 && TempBitDepth != 8 && TempBitDepth != 16
823 && TempBitDepth != 24 && TempBitDepth != 32 )
825 if( EasyBMPwarnings )
827 cout << "EasyBMP Error: " << FileName << " has unrecognized bit depth." << endl;
834 SetBitDepth( (int) bmih.biBitCount );
838 if( (int) bmih.biWidth <= 0 || (int) bmih.biHeight <= 0 )
840 if( EasyBMPwarnings )
842 cout << "EasyBMP Error: " << FileName
843 << " has a non-positive width or height." << endl;
850 SetSize( (int) bmih.biWidth , (int) bmih.biHeight );
852 // some preliminaries
854 double dBytesPerPixel = ( (double) BitDepth ) / 8.0;
855 double dBytesPerRow = dBytesPerPixel * (Width+0.0);
856 dBytesPerRow = ceil(dBytesPerRow);
858 int BytePaddingPerRow = 4 - ( (int) (dBytesPerRow) )% 4;
859 if( BytePaddingPerRow == 4 )
860 { BytePaddingPerRow = 0; }
862 // if < 16 bits, read the palette
866 // determine the number of colors specified in the
869 int NumberOfColorsToRead = ((int) bmfh.bfOffBits - 54 )/4;
870 if( NumberOfColorsToRead > IntPow(2,BitDepth) )
871 { NumberOfColorsToRead = IntPow(2,BitDepth); }
873 if( NumberOfColorsToRead < TellNumberOfColors() )
875 if( EasyBMPwarnings )
877 cout << "EasyBMP Warning: file " << FileName << " has an underspecified" << endl
878 << " color table. The table will be padded with extra" << endl
879 << " white (255,255,255,0) entries." << endl;
884 for( n=0; n < NumberOfColorsToRead ; n++ )
886 SafeFread( (char*) &(Colors[n]) , 4 , 1 , fp);
888 for( n=NumberOfColorsToRead ; n < TellNumberOfColors() ; n++ )
895 SetColor( n , WHITE );
901 // skip blank data if bfOffBits so indicates
903 int BytesToSkip = bmfh.bfOffBits - 54;;
905 { BytesToSkip -= 4*IntPow(2,BitDepth); }
906 if( BitDepth == 16 && bmih.biCompression == 3 )
907 { BytesToSkip -= 3*4; }
908 if( BytesToSkip < 0 )
910 if( BytesToSkip > 0 && BitDepth != 16 )
912 if( EasyBMPwarnings )
914 cout << "EasyBMP Warning: Extra meta data detected in file " << FileName << endl
915 << " Data will be skipped." << endl;
917 ebmpBYTE* TempSkipBYTE;
918 TempSkipBYTE = new ebmpBYTE [BytesToSkip];
919 SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
\r
920 delete [] TempSkipBYTE;
923 // This code reads 1, 4, 8, 24, and 32-bpp files
924 // with a more-efficient buffered technique.
929 int BufferSize = (int) ( (Width*BitDepth) / 8.0 );
930 while( 8*BufferSize < Width*BitDepth )
932 while( BufferSize % 4 )
935 Buffer = new ebmpBYTE [BufferSize];
939 int BytesRead = (int) fread( (char*) Buffer, 1, BufferSize, fp );
940 if( BytesRead < BufferSize )
943 if( EasyBMPwarnings )
945 cout << "EasyBMP Error: Could not read proper amount of data." << endl;
950 bool Success = false;
952 { Success = Read1bitRow( Buffer, BufferSize, j ); }
954 { Success = Read4bitRow( Buffer, BufferSize, j ); }
956 { Success = Read8bitRow( Buffer, BufferSize, j ); }
958 { Success = Read24bitRow( Buffer, BufferSize, j ); }
960 { Success = Read32bitRow( Buffer, BufferSize, j ); }
963 if( EasyBMPwarnings )
965 cout << "EasyBMP Error: Could not read enough pixel data!" << endl;
977 int DataBytes = Width*2;
978 int PaddingBytes = ( 4 - DataBytes % 4 ) % 4;
980 // set the default mask
982 ebmpWORD BlueMask = 31; // bits 12-16
983 ebmpWORD GreenMask = 992; // bits 7-11
984 ebmpWORD RedMask = 31744; // bits 2-6
986 // read the bit fields, if necessary, to
987 // override the default 5-5-5 mask
989 if( bmih.biCompression != 0 )
991 // read the three bit masks
993 ebmpWORD TempMaskWORD;
996 SafeFread( (char*) &RedMask , 2 , 1 , fp );
998 { RedMask = FlipWORD(RedMask); }
999 SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1001 SafeFread( (char*) &GreenMask , 2 , 1 , fp );
1003 { GreenMask = FlipWORD(GreenMask); }
1004 SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1006 SafeFread( (char*) &BlueMask , 2 , 1 , fp );
1008 { BlueMask = FlipWORD(BlueMask); }
1009 SafeFread( (char*) &TempMaskWORD , 2, 1, fp );
1012 // read and skip any meta data
1014 if( BytesToSkip > 0 )
1016 if( EasyBMPwarnings )
1018 cout << "EasyBMP Warning: Extra meta data detected in file "
1020 << " Data will be skipped." << endl;
1022 ebmpBYTE* TempSkipBYTE;
1023 TempSkipBYTE = new ebmpBYTE [BytesToSkip];
1024 SafeFread( (char*) TempSkipBYTE , BytesToSkip , 1 , fp);
\r
1025 delete [] TempSkipBYTE;
1028 // determine the red, green and blue shifts
1031 ebmpWORD TempShiftWORD = GreenMask;
1032 while( TempShiftWORD > 31 )
1033 { TempShiftWORD = TempShiftWORD>>1; GreenShift++; }
1035 TempShiftWORD = BlueMask;
1036 while( TempShiftWORD > 31 )
1037 { TempShiftWORD = TempShiftWORD>>1; BlueShift++; }
1039 TempShiftWORD = RedMask;
1040 while( TempShiftWORD > 31 )
1041 { TempShiftWORD = TempShiftWORD>>1; RedShift++; }
1043 // read the actual pixels
1045 for( j=Height-1 ; j >= 0 ; j-- )
1049 while( ReadNumber < DataBytes )
1052 SafeFread( (char*) &TempWORD , 2 , 1 , fp );
1054 { TempWORD = FlipWORD(TempWORD); }
1057 ebmpWORD Red = RedMask & TempWORD;
1058 ebmpWORD Green = GreenMask & TempWORD;
1059 ebmpWORD Blue = BlueMask & TempWORD;
1061 ebmpBYTE BlueBYTE = (ebmpBYTE) 8*(Blue>>BlueShift);
1062 ebmpBYTE GreenBYTE = (ebmpBYTE) 8*(Green>>GreenShift);
1063 ebmpBYTE RedBYTE = (ebmpBYTE) 8*(Red>>RedShift);
1065 (Pixels[i][j]).Red = RedBYTE;
1066 (Pixels[i][j]).Green = GreenBYTE;
1067 (Pixels[i][j]).Blue = BlueBYTE;
1072 while( ReadNumber < PaddingBytes )
1075 SafeFread( (char*) &TempBYTE , 1, 1, fp);
1086 bool BMP::CreateStandardColorTable( void )
1088 using namespace std;
1089 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
1091 if( EasyBMPwarnings )
1093 cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
1094 << " depth that does not require a color table." << endl
1095 << " Ignoring request." << endl;
1103 for( i=0 ; i < 2 ; i++ )
1105 Colors[i].Red = i*255;
1106 Colors[i].Green = i*255;
1107 Colors[i].Blue = i*255;
1108 Colors[i].Alpha = 0;
1118 // simplify the code for the first 8 colors
1119 for( ell=0 ; ell < 2 ; ell++ )
1121 for( k=0 ; k < 2 ; k++ )
1123 for( j=0 ; j < 2 ; j++ )
1125 Colors[i].Red = j*128;
1126 Colors[i].Green = k*128;
1127 Colors[i].Blue = ell*128;
1133 // simplify the code for the last 8 colors
1134 for( ell=0 ; ell < 2 ; ell++ )
1136 for( k=0 ; k < 2 ; k++ )
1138 for( j=0 ; j < 2 ; j++ )
1140 Colors[i].Red = j*255;
1141 Colors[i].Green = k*255;
1142 Colors[i].Blue = ell*255;
1148 // overwrite the duplicate color
1150 Colors[i].Red = 192;
1151 Colors[i].Green = 192;
1152 Colors[i].Blue = 192;
1154 for( i=0 ; i < 16 ; i++ )
1155 { Colors[i].Alpha = 0; }
1164 // do an easy loop, which works for all but colors
1165 // 0 to 9 and 246 to 255
1166 for( ell=0 ; ell < 4 ; ell++ )
1168 for( k=0 ; k < 8 ; k++ )
1170 for( j=0; j < 8 ; j++ )
1172 Colors[i].Red = j*32;
1173 Colors[i].Green = k*32;
1174 Colors[i].Blue = ell*64;
1175 Colors[i].Alpha = 0;
1181 // now redo the first 8 colors
1183 for( ell=0 ; ell < 2 ; ell++ )
1185 for( k=0 ; k < 2 ; k++ )
1187 for( j=0; j < 2 ; j++ )
1189 Colors[i].Red = j*128;
1190 Colors[i].Green = k*128;
1191 Colors[i].Blue = ell*128;
1197 // overwrite colors 7, 8, 9
1199 Colors[i].Red = 192;
1200 Colors[i].Green = 192;
1201 Colors[i].Blue = 192;
1203 Colors[i].Red = 192;
1204 Colors[i].Green = 220;
1205 Colors[i].Blue = 192;
1207 Colors[i].Red = 166;
1208 Colors[i].Green = 202;
1209 Colors[i].Blue = 240;
1211 // overwrite colors 246 to 255
1213 Colors[i].Red = 255;
1214 Colors[i].Green = 251;
1215 Colors[i].Blue = 240;
1217 Colors[i].Red = 160;
1218 Colors[i].Green = 160;
1219 Colors[i].Blue = 164;
1221 Colors[i].Red = 128;
1222 Colors[i].Green = 128;
1223 Colors[i].Blue = 128;
1225 Colors[i].Red = 255;
1226 Colors[i].Green = 0;
1230 Colors[i].Green = 255;
1233 Colors[i].Red = 255;
1234 Colors[i].Green = 255;
1238 Colors[i].Green = 0;
1239 Colors[i].Blue = 255;
1241 Colors[i].Red = 255;
1242 Colors[i].Green = 0;
1243 Colors[i].Blue = 255;
1246 Colors[i].Green = 255;
1247 Colors[i].Blue = 255;
1249 Colors[i].Red = 255;
1250 Colors[i].Green = 255;
1251 Colors[i].Blue = 255;
1258 bool SafeFread( char* buffer, int size, int number, FILE* fp )
1260 using namespace std;
1264 ItemsRead = (int) fread( buffer , size , number , fp );
1265 if( ItemsRead < number )
1270 void BMP::SetDPI( int HorizontalDPI, int VerticalDPI )
1272 XPelsPerMeter = (int) ( HorizontalDPI * 39.37007874015748 );
1273 YPelsPerMeter = (int) ( VerticalDPI * 39.37007874015748 );
1276 // int BMP::TellVerticalDPI( void ) const
\r
1277 int BMP::TellVerticalDPI( void )
\r
1279 if( !YPelsPerMeter )
\r
1280 { YPelsPerMeter = DefaultYPelsPerMeter; }
\r
1281 return (int) ( YPelsPerMeter / (double) 39.37007874015748 );
\r
1284 // int BMP::TellHorizontalDPI( void ) const
\r
1285 int BMP::TellHorizontalDPI( void )
\r
1287 if( !XPelsPerMeter )
\r
1288 { XPelsPerMeter = DefaultXPelsPerMeter; }
\r
1289 return (int) ( XPelsPerMeter / (double) 39.37007874015748 );
\r
1292 /* These functions are defined in EasyBMP_VariousBMPutilities.h */
\r
1294 BMFH GetBMFH( const char* szFileNameIn )
1296 using namespace std;
1300 fp = fopen( szFileNameIn,"rb");
1304 if( EasyBMPwarnings )
1306 cout << "EasyBMP Error: Cannot initialize from file "
1307 << szFileNameIn << "." << endl
1308 << " File cannot be opened or does not exist."
1315 SafeFread( (char*) &(bmfh.bfType) , sizeof(ebmpWORD) , 1 , fp );
1316 SafeFread( (char*) &(bmfh.bfSize) , sizeof(ebmpDWORD) , 1 , fp );
1317 SafeFread( (char*) &(bmfh.bfReserved1) , sizeof(ebmpWORD) , 1 , fp );
1318 SafeFread( (char*) &(bmfh.bfReserved2) , sizeof(ebmpWORD) , 1 , fp );
1319 SafeFread( (char*) &(bmfh.bfOffBits) , sizeof(ebmpDWORD) , 1 , fp );
1324 { bmfh.SwitchEndianess(); }
1329 BMIH GetBMIH( const char* szFileNameIn )
1331 using namespace std;
1336 fp = fopen( szFileNameIn,"rb");
1340 if( EasyBMPwarnings )
1342 cout << "EasyBMP Error: Cannot initialize from file "
1343 << szFileNameIn << "." << endl
1344 << " File cannot be opened or does not exist."
1350 // read the bmfh, i.e., first 14 bytes (just to get it out of the way);
1354 for( i = 14 ; i > 0 ; i-- )
1355 { SafeFread( (char*) &TempBYTE , sizeof(ebmpBYTE) , 1, fp ); }
1359 SafeFread( (char*) &(bmih.biSize) , sizeof(ebmpDWORD) , 1 , fp );
1360 SafeFread( (char*) &(bmih.biWidth) , sizeof(ebmpDWORD) , 1 , fp );
1361 SafeFread( (char*) &(bmih.biHeight) , sizeof(ebmpDWORD) , 1 , fp );
1362 SafeFread( (char*) &(bmih.biPlanes) , sizeof(ebmpWORD) , 1 , fp );
1364 SafeFread( (char*) &(bmih.biBitCount) , sizeof(ebmpWORD) , 1 , fp );
1365 SafeFread( (char*) &(bmih.biCompression) , sizeof(ebmpDWORD) , 1 , fp );
1366 SafeFread( (char*) &(bmih.biSizeImage) , sizeof(ebmpDWORD) , 1 , fp );
1367 SafeFread( (char*) &(bmih.biXPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
1369 SafeFread( (char*) &(bmih.biYPelsPerMeter) , sizeof(ebmpDWORD) , 1 , fp );
1370 SafeFread( (char*) &(bmih.biClrUsed) , sizeof(ebmpDWORD) , 1 , fp );
1371 SafeFread( (char*) &(bmih.biClrImportant) , sizeof(ebmpDWORD) , 1 , fp );
1376 { bmih.SwitchEndianess(); }
1381 void DisplayBitmapInfo( const char* szFileNameIn )
1383 using namespace std;
1385 fp = fopen( szFileNameIn,"rb");
1389 if( EasyBMPwarnings )
1391 cout << "EasyBMP Error: Cannot initialize from file "
1392 << szFileNameIn << "." << endl
1393 << " File cannot be opened or does not exist."
1400 // don't duplicate work! Just use the functions from above!
1402 BMFH bmfh = GetBMFH(szFileNameIn);
1403 BMIH bmih = GetBMIH(szFileNameIn);
1405 cout << "File information for file " << szFileNameIn
1406 << ":" << endl << endl;
1408 cout << "BITMAPFILEHEADER:" << endl
1409 << "bfType: " << bmfh.bfType << endl
1410 << "bfSize: " << bmfh.bfSize << endl
1411 << "bfReserved1: " << bmfh.bfReserved1 << endl
1412 << "bfReserved2: " << bmfh.bfReserved2 << endl
1413 << "bfOffBits: " << bmfh.bfOffBits << endl << endl;
1415 cout << "BITMAPINFOHEADER:" << endl
1416 << "biSize: " << bmih.biSize << endl
1417 << "biWidth: " << bmih.biWidth << endl
1418 << "biHeight: " << bmih.biHeight << endl
1419 << "biPlanes: " << bmih.biPlanes << endl
1420 << "biBitCount: " << bmih.biBitCount << endl
1421 << "biCompression: " << bmih.biCompression << endl
1422 << "biSizeImage: " << bmih.biSizeImage << endl
1423 << "biXPelsPerMeter: " << bmih.biXPelsPerMeter << endl
1424 << "biYPelsPerMeter: " << bmih.biYPelsPerMeter << endl
1425 << "biClrUsed: " << bmih.biClrUsed << endl
1426 << "biClrImportant: " << bmih.biClrImportant << endl << endl;
1430 int GetBitmapColorDepth( const char* szFileNameIn )
1432 BMIH bmih = GetBMIH( szFileNameIn );
1433 return (int) bmih.biBitCount;
1436 void PixelToPixelCopy( BMP& From, int FromX, int FromY,
1437 BMP& To, int ToX, int ToY)
1439 *To(ToX,ToY) = *From(FromX,FromY);
1443 void PixelToPixelCopyTransparent( BMP& From, int FromX, int FromY,
1444 BMP& To, int ToX, int ToY,
1445 RGBApixel& Transparent )
1447 if( From(FromX,FromY)->Red != Transparent.Red ||
1448 From(FromX,FromY)->Green != Transparent.Green ||
1449 From(FromX,FromY)->Blue != Transparent.Blue )
1450 { *To(ToX,ToY) = *From(FromX,FromY); }
1454 void RangedPixelToPixelCopy( BMP& From, int FromL , int FromR, int FromB, int FromT,
1455 BMP& To, int ToX, int ToY )
1457 // make sure the conventions are followed
1459 { int Temp = FromT; FromT = FromB; FromB = Temp; }
1461 // make sure that the copied regions exist in both bitmaps
1462 if( FromR >= From.TellWidth() )
1463 { FromR = From.TellWidth()-1; }
1464 if( FromL < 0 ){ FromL = 0; }
1466 if( FromB >= From.TellHeight() )
1467 { FromB = From.TellHeight()-1; }
1468 if( FromT < 0 ){ FromT = 0; }
1470 if( ToX+(FromR-FromL) >= To.TellWidth() )
1471 { FromR = To.TellWidth()-1+FromL-ToX; }
1472 if( ToY+(FromB-FromT) >= To.TellHeight() )
1473 { FromB = To.TellHeight()-1+FromT-ToY; }
1476 for( j=FromT ; j <= FromB ; j++ )
1478 for( i=FromL ; i <= FromR ; i++ )
1480 PixelToPixelCopy( From, i,j,
1481 To, ToX+(i-FromL), ToY+(j-FromT) );
1488 void RangedPixelToPixelCopyTransparent(
1489 BMP& From, int FromL , int FromR, int FromB, int FromT,
1490 BMP& To, int ToX, int ToY ,
1491 RGBApixel& Transparent )
1493 // make sure the conventions are followed
1495 { int Temp = FromT; FromT = FromB; FromB = Temp; }
1497 // make sure that the copied regions exist in both bitmaps
1498 if( FromR >= From.TellWidth() )
1499 { FromR = From.TellWidth()-1; }
1500 if( FromL < 0 ){ FromL = 0; }
1502 if( FromB >= From.TellHeight() )
1503 { FromB = From.TellHeight()-1; }
1504 if( FromT < 0 ){ FromT = 0; }
1506 if( ToX+(FromR-FromL) >= To.TellWidth() )
1507 { FromR = To.TellWidth()-1+FromL-ToX; }
1508 if( ToY+(FromB-FromT) >= To.TellHeight() )
1509 { FromB = To.TellHeight()-1+FromT-ToY; }
1512 for( j=FromT ; j <= FromB ; j++ )
1514 for( i=FromL ; i <= FromR ; i++ )
1516 PixelToPixelCopyTransparent( From, i,j,
1517 To, ToX+(i-FromL), ToY+(j-FromT) ,
1525 bool CreateGrayscaleColorTable( BMP& InputImage )
1527 using namespace std;
1528 int BitDepth = InputImage.TellBitDepth();
1529 if( BitDepth != 1 && BitDepth != 4 && BitDepth != 8 )
1531 if( EasyBMPwarnings )
1533 cout << "EasyBMP Warning: Attempted to create color table at a bit" << endl
1534 << " depth that does not require a color table." << endl
1535 << " Ignoring request." << endl;
1540 int NumberOfColors = InputImage.TellNumberOfColors();
1544 { StepSize = 255/(NumberOfColors-1); }
1548 for( i=0 ; i < NumberOfColors ; i++ )
1550 ebmpBYTE TempBYTE = i*StepSize;
1551 RGBApixel TempColor;
1552 TempColor.Red = TempBYTE;
1553 TempColor.Green = TempBYTE;
1554 TempColor.Blue = TempBYTE;
1555 TempColor.Alpha = 0;
1556 InputImage.SetColor( i , TempColor );
1561 bool BMP::Read32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1564 if( Width*4 > BufferSize )
1566 for( i=0 ; i < Width ; i++ )
1567 { memcpy( (char*) &(Pixels[i][Row]), (char*) Buffer+4*i, 4 ); }
1571 bool BMP::Read24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1574 if( Width*3 > BufferSize )
1576 for( i=0 ; i < Width ; i++ )
1577 { memcpy( (char*) &(Pixels[i][Row]), Buffer+3*i, 3 ); }
1581 bool BMP::Read8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1584 if( Width > BufferSize )
1586 for( i=0 ; i < Width ; i++ )
1588 int Index = Buffer[i];
1589 *( this->operator()(i,Row) )= GetColor(Index);
1594 bool BMP::Read4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1596 int Shifts[2] = {4 ,0 };
1597 int Masks[2] = {240,15};
1602 if( Width > 2*BufferSize )
1607 while( j < 2 && i < Width )
1609 int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
1610 *( this->operator()(i,Row) )= GetColor(Index);
1617 bool BMP::Read1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1619 int Shifts[8] = {7 ,6 ,5 ,4 ,3,2,1,0};
1620 int Masks[8] = {128,64,32,16,8,4,2,1};
1626 if( Width > 8*BufferSize )
1631 while( j < 8 && i < Width )
1633 int Index = (int) ( (Buffer[k]&Masks[j]) >> Shifts[j]);
1634 *( this->operator()(i,Row) )= GetColor(Index);
1642 bool BMP::Write32bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1645 if( Width*4 > BufferSize )
1647 for( i=0 ; i < Width ; i++ )
1648 { memcpy( (char*) Buffer+4*i, (char*) &(Pixels[i][Row]), 4 ); }
1652 bool BMP::Write24bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1655 if( Width*3 > BufferSize )
1657 for( i=0 ; i < Width ; i++ )
1658 { memcpy( (char*) Buffer+3*i, (char*) &(Pixels[i][Row]), 3 ); }
1662 bool BMP::Write8bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1665 if( Width > BufferSize )
1667 for( i=0 ; i < Width ; i++ )
1668 { Buffer[i] = FindClosestColor( Pixels[i][Row] ); }
1672 bool BMP::Write4bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1674 int PositionWeights[2] = {16,1};
1679 if( Width > 2*BufferSize )
1685 while( j < 2 && i < Width )
1687 Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) );
1690 Buffer[k] = (ebmpBYTE) Index;
1696 bool BMP::Write1bitRow( ebmpBYTE* Buffer, int BufferSize, int Row )
1698 int PositionWeights[8] = {128,64,32,16,8,4,2,1};
1703 if( Width > 8*BufferSize )
1709 while( j < 8 && i < Width )
1711 Index += ( PositionWeights[j]* (int) FindClosestColor( Pixels[i][Row] ) );
1714 Buffer[k] = (ebmpBYTE) Index;
1720 ebmpBYTE BMP::FindClosestColor( RGBApixel& input )
1722 using namespace std;
1725 int NumberOfColors = TellNumberOfColors();
1727 int BestMatch = 999999;
1729 while( i < NumberOfColors )
1731 RGBApixel Attempt = GetColor( i );
1732 int TempMatch = IntSquare( (int) Attempt.Red - (int) input.Red )
1733 + IntSquare( (int) Attempt.Green - (int) input.Green )
1734 + IntSquare( (int) Attempt.Blue - (int) input.Blue );
1735 if( TempMatch < BestMatch )
1736 { BestI = (ebmpBYTE) i; BestMatch = TempMatch; }
1738 { i = NumberOfColors; }
1744 bool EasyBMPcheckDataSize( void )
1746 using namespace std;
1747 bool ReturnValue = true;
1748 if( sizeof( ebmpBYTE ) != 1 )
1750 if( EasyBMPwarnings )
1752 cout << "EasyBMP Error: ebmpBYTE has the wrong size ("
1753 << sizeof( ebmpBYTE ) << " bytes)," << endl
1754 << " Compared to the expected 1 byte value" << endl;
1756 ReturnValue = false;
1758 if( sizeof( ebmpWORD ) != 2 )
1760 if( EasyBMPwarnings )
1762 cout << "EasyBMP Error: ebmpWORD has the wrong size ("
1763 << sizeof( ebmpWORD ) << " bytes)," << endl
1764 << " Compared to the expected 2 byte value" << endl;
1766 ReturnValue = false;
1768 if( sizeof( ebmpDWORD ) != 4 )
1770 if( EasyBMPwarnings )
1772 cout << "EasyBMP Error: ebmpDWORD has the wrong size ("
1773 << sizeof( ebmpDWORD ) << " bytes)," << endl
1774 << " Compared to the expected 4 byte value" << endl;
1776 ReturnValue = false;
1781 bool Rescale( BMP& InputImage , char mode, int NewDimension )
1783 using namespace std;
1784 int CapMode = toupper( mode );
1786 BMP OldImage( InputImage );
1788 if( CapMode != 'P' &&
1793 if( EasyBMPwarnings )
1795 char ErrorMessage [1024];
1796 sprintf( ErrorMessage, "EasyBMP Error: Unknown rescale mode %c requested\n" , mode );
1797 cout << ErrorMessage;
1805 int OldWidth = OldImage.TellWidth();
1806 int OldHeight= OldImage.TellHeight();
1808 if( CapMode == 'P' )
1810 NewWidth = (int) floor( OldWidth * NewDimension / 100.0 );
1811 NewHeight = (int) floor( OldHeight * NewDimension / 100.0 );
1813 if( CapMode == 'F' )
1815 if( OldWidth > OldHeight )
1821 if( CapMode == 'W' )
1823 double percent = (double) NewDimension / (double) OldWidth;
1824 NewWidth = NewDimension;
1825 NewHeight = (int) floor( OldHeight * percent );
1827 if( CapMode == 'H' )
1829 double percent = (double) NewDimension / (double) OldHeight;
1830 NewHeight = NewDimension;
1831 NewWidth = (int) floor( OldWidth * percent );
1839 InputImage.SetSize( NewWidth, NewHeight );
1840 InputImage.SetBitDepth( 24 );
1843 double ThetaI,ThetaJ;
1845 for( int j=0; j < NewHeight-1 ; j++ )
1847 ThetaJ = (double)(j*(OldHeight-1.0))
1848 /(double)(NewHeight-1.0);
1849 J = (int) floor( ThetaJ );
1852 for( int i=0; i < NewWidth-1 ; i++ )
1854 ThetaI = (double)(i*(OldWidth-1.0))
1855 /(double)(NewWidth-1.0);
1856 I = (int) floor( ThetaI );
1859 InputImage(i,j)->Red = (ebmpBYTE)
1860 ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*(OldImage(I,J)->Red)
1861 +(ThetaI-ThetaI*ThetaJ)*(OldImage(I+1,J)->Red)
1862 +(ThetaJ-ThetaI*ThetaJ)*(OldImage(I,J+1)->Red)
1863 +(ThetaI*ThetaJ)*(OldImage(I+1,J+1)->Red) );
1864 InputImage(i,j)->Green = (ebmpBYTE)
1865 ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Green
1866 +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Green
1867 +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Green
1868 +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Green );
1869 InputImage(i,j)->Blue = (ebmpBYTE)
1870 ( (1.0-ThetaI-ThetaJ+ThetaI*ThetaJ)*OldImage(I,J)->Blue
1871 +(ThetaI-ThetaI*ThetaJ)*OldImage(I+1,J)->Blue
1872 +(ThetaJ-ThetaI*ThetaJ)*OldImage(I,J+1)->Blue
1873 +(ThetaI*ThetaJ)*OldImage(I+1,J+1)->Blue );
1875 InputImage(NewWidth-1,j)->Red = (ebmpBYTE)
1876 ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Red)
1877 + ThetaJ*(OldImage(OldWidth-1,J+1)->Red) );
1878 InputImage(NewWidth-1,j)->Green = (ebmpBYTE)
1879 ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Green)
1880 + ThetaJ*(OldImage(OldWidth-1,J+1)->Green) );
1881 InputImage(NewWidth-1,j)->Blue = (ebmpBYTE)
1882 ( (1.0-ThetaJ)*(OldImage(OldWidth-1,J)->Blue)
1883 + ThetaJ*(OldImage(OldWidth-1,J+1)->Blue) );
1886 for( int i=0 ; i < NewWidth-1 ; i++ )
1888 ThetaI = (double)(i*(OldWidth-1.0))
1889 /(double)(NewWidth-1.0);
1890 I = (int) floor( ThetaI );
1892 InputImage(i,NewHeight-1)->Red = (ebmpBYTE)
1893 ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Red)
1894 + ThetaI*(OldImage(I,OldHeight-1)->Red) );
1895 InputImage(i,NewHeight-1)->Green = (ebmpBYTE)
1896 ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Green)
1897 + ThetaI*(OldImage(I,OldHeight-1)->Green) );
1898 InputImage(i,NewHeight-1)->Blue = (ebmpBYTE)
1899 ( (1.0-ThetaI)*(OldImage(I,OldHeight-1)->Blue)
1900 + ThetaI*(OldImage(I,OldHeight-1)->Blue) );
1903 *InputImage(NewWidth-1,NewHeight-1) = *OldImage(OldWidth-1,OldHeight-1);