fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGBMPImageFileType.cpp
blob7386499b8de8a8afa0deb6411b0ad6df2e0daa14
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 //-------------------------------
39 // Includes
40 //-------------------------------
42 #include <cstdlib>
43 #include <cstdio>
45 #include "OSGConfig.h"
47 #include "OSGBMPImageFileType.h"
48 #include "OSGLog.h"
50 #include <iostream>
52 OSG_BEGIN_NAMESPACE
54 /*! \class BMPImageFileType
56 Image File Type to read/write and store/restore Image objects as
57 BMP data.
59 All the type specific code is included in the class. Does
60 not depend on external libs.
62 @author Patrick D&auml;hne
66 namespace
68 UInt32 parseUInt32(char *&ptr)
70 UInt32 result =
71 (static_cast<UInt32>(static_cast<UInt8>(ptr[0])) << 0) |
72 (static_cast<UInt32>(static_cast<UInt8>(ptr[1])) << 8) |
73 (static_cast<UInt32>(static_cast<UInt8>(ptr[2])) << 16) |
74 (static_cast<UInt32>(static_cast<UInt8>(ptr[3])) << 24);
75 ptr += 4;
76 return result;
79 UInt16 parseUInt16(char *&ptr)
81 UInt16 result =
82 (static_cast<UInt32>(static_cast<UInt8>(ptr[0])) << 0) |
83 (static_cast<UInt32>(static_cast<UInt8>(ptr[1])) << 8);
84 ptr +=2;
85 return result;
88 struct OSGBITMAPFILEHEADER
90 Int8 bfType[2];
91 UInt32 bfSize;
92 UInt16 bfReserved1;
93 UInt16 bfReserved2;
94 UInt32 bfOffBits;
97 struct OSGBITMAPINFOHEADER
99 UInt32 biSize;
100 UInt32 biWidth;
101 Int32 biHeight; // Not a typo - height can be negative
102 UInt16 biPlanes;
103 UInt16 biBitCount;
104 UInt32 biCompression;
105 UInt32 biSizeImage;
106 UInt32 biXPelsPerMeter;
107 UInt32 biYPelsPerMeter;
108 UInt32 biClrUsed;
109 UInt32 biClrImportant;
110 UInt32 redMask;
111 UInt32 greenMask;
112 UInt32 blueMask;
113 UInt32 alphaMask;
116 struct RGB
118 UInt8 r, g, b;
121 bool readBitmapFileHeader(std::istream &is, OSGBITMAPFILEHEADER &header)
123 // Read the header
124 char buffer[14];
125 is.read(buffer, 14);
126 if (is.gcount() != 14)
127 return false;
129 // Parse the header
130 char *ptr = buffer;
131 memcpy(header.bfType, ptr, 2);
132 ptr += 2;
133 header.bfSize = parseUInt32(ptr);
134 header.bfReserved1 = parseUInt16(ptr);
135 header.bfReserved2 = parseUInt16(ptr);
136 header.bfOffBits = parseUInt32(ptr);
138 // Check the header
139 if (memcmp(header.bfType, "BM", 2) != 0)
140 return false;
142 return true;
145 bool readBitmapInfoHeader(std::istream &is, OSGBITMAPINFOHEADER &infoHeader)
147 // Determine size of the header
148 char buffer[56];
149 is.read(buffer, 4);
150 if (is.gcount() != 4)
151 return false;
152 char *ptr = buffer;
153 infoHeader.biSize = parseUInt32(ptr);
155 infoHeader.redMask = 0;
156 infoHeader.greenMask = 0;
157 infoHeader.blueMask = 0;
158 infoHeader.alphaMask = 0;
160 // Parse the header
161 if (infoHeader.biSize >= 40)
163 // Read the remaining header
164 int size = infoHeader.biSize >= 56 ? 56 - 4 : 40 - 4;
165 is.read(&(buffer[4]), size);
166 if (is.gcount() != size)
167 return false;
169 infoHeader.biWidth = parseUInt32(ptr);
170 infoHeader.biHeight = parseUInt32(ptr);
171 infoHeader.biPlanes = parseUInt16(ptr);
172 infoHeader.biBitCount = parseUInt16(ptr);
173 infoHeader.biCompression = parseUInt32(ptr);
174 infoHeader.biSizeImage = parseUInt32(ptr);
175 infoHeader.biXPelsPerMeter = parseUInt32(ptr);
176 infoHeader.biYPelsPerMeter = parseUInt32(ptr);
177 infoHeader.biClrUsed = parseUInt32(ptr);
178 infoHeader.biClrImportant = parseUInt32(ptr);
180 if ((infoHeader.biSize >= 56) && (infoHeader.biCompression == 3 /*BI_BITFIELDS*/))
182 infoHeader.redMask = parseUInt32(ptr);
183 infoHeader.greenMask = parseUInt32(ptr);
184 infoHeader.blueMask = parseUInt32(ptr);
185 infoHeader.alphaMask = parseUInt32(ptr);
187 else
188 infoHeader.alphaMask = 0;
190 is.ignore(infoHeader.biSize - size - 4);
192 else if (infoHeader.biSize >= 12)
194 // Read the remaining header
195 is.read(&(buffer[4]), 12 - 4);
196 if (is.gcount() != 12 - 4)
197 return false;
199 infoHeader.biWidth = parseUInt16(ptr);
200 infoHeader.biHeight = parseUInt16(ptr);
201 infoHeader.biPlanes = parseUInt16(ptr);
202 infoHeader.biBitCount = parseUInt16(ptr);
203 infoHeader.biCompression = 0;
204 infoHeader.biSizeImage = 0;
205 infoHeader.biXPelsPerMeter = 0;
206 infoHeader.biYPelsPerMeter = 0;
207 infoHeader.biClrUsed = 0;
208 infoHeader.biClrImportant = 0;
210 is.ignore(infoHeader.biSize - 12);
212 else
213 return false;
215 // Check header
216 if ((infoHeader.biBitCount != 1) &&
217 (infoHeader.biBitCount != 4) &&
218 (infoHeader.biBitCount != 8) &&
219 (infoHeader.biBitCount != 16) &&
220 (infoHeader.biBitCount != 24) &&
221 (infoHeader.biBitCount != 32))
222 return false;
223 if (infoHeader.biPlanes != 1)
224 return false;
225 if ((infoHeader.biBitCount == 1) && (infoHeader.biCompression != 0 /*BI_RGB*/))
226 return false;
227 if ((infoHeader.biBitCount == 4) && (infoHeader.biCompression != 0 /*BI_RGB*/) &&
228 (infoHeader.biCompression != 2 /*BI_RLE4*/))
229 return false;
230 if ((infoHeader.biBitCount == 8) && (infoHeader.biCompression != 0 /*BI_RGB*/) &&
231 (infoHeader.biCompression != 1 /*BI_RLE8*/))
232 return false;
233 if ((infoHeader.biBitCount == 16) && (infoHeader.biCompression != 0 /*BI_RGB*/) &&
234 (infoHeader.biCompression != 3 /*BI_BITFIELDS*/))
235 return false;
236 if ((infoHeader.biBitCount == 24) && (infoHeader.biCompression != 0 /*BI_RGB*/))
237 return false;
238 if ((infoHeader.biBitCount == 32) && (infoHeader.biCompression != 0 /*BI_RGB*/) &&
239 (infoHeader.biCompression != 3 /*BI_BITFIELDS*/))
240 return false;
242 if (infoHeader.biSize < 56)
244 if (infoHeader.biCompression == 3 /*BI_BITFIELDS*/)
246 is.read(buffer, 12);
247 if (is.gcount() != 12)
248 return false;
249 ptr = buffer;
250 infoHeader.redMask = parseUInt32(ptr);
251 infoHeader.greenMask = parseUInt32(ptr);
252 infoHeader.blueMask = parseUInt32(ptr);
253 infoHeader.alphaMask = 0;
254 infoHeader.biSize += 12;
256 else if (infoHeader.biBitCount == 16)
258 infoHeader.redMask = 0x7c00;
259 infoHeader.greenMask = 0x03e0;
260 infoHeader.blueMask = 0x001f;
261 infoHeader.alphaMask = 0;
263 else if (infoHeader.biBitCount == 32)
265 infoHeader.redMask = 0x00ff0000;
266 infoHeader.greenMask = 0x0000ff00;
267 infoHeader.blueMask = 0x000000ff;
268 infoHeader.alphaMask = 0xff000000;
272 #if 0
273 std::cout << "infoHeader.biSize = " << infoHeader.biSize << std::endl;
274 std::cout << "infoHeader.biWidth = " << infoHeader.biWidth << std::endl;
275 std::cout << "infoHeader.biHeight = " << infoHeader.biHeight << std::endl;
276 std::cout << "infoHeader.biPlanes = " << infoHeader.biPlanes << std::endl;
277 std::cout << "infoHeader.biBitCount = " << infoHeader.biBitCount << std::endl;
278 std::cout << "infoHeader.biCompression = " << infoHeader.biCompression << std::endl;
279 #endif
281 return true;
284 bool readColorMap(std::istream &is, const OSGBITMAPFILEHEADER &fileHeader,
285 const OSGBITMAPINFOHEADER &infoHeader, RGB colorMap[256])
287 if (infoHeader.biBitCount <= 8)
289 UInt32 nCols = 1 << infoHeader.biBitCount;
290 if (infoHeader.biClrUsed > 0)
292 if (infoHeader.biClrUsed > nCols)
293 return false;
294 nCols = infoHeader.biClrUsed;
296 int bytesPerColor = (infoHeader.biSize < 40) || (infoHeader.biSize + 14 + 4 * nCols > fileHeader.bfOffBits)
297 ? 3 : 4;
298 char buffer[256 * 4];
299 is.read(buffer, nCols * bytesPerColor);
300 if (static_cast<UInt32>(is.gcount()) != nCols * bytesPerColor)
301 return false;
302 char *ptr = buffer;
303 for (UInt32 i = 0; i < nCols; ++i)
305 colorMap[i].r = ptr[2];
306 colorMap[i].g = ptr[1];
307 colorMap[i].b = ptr[0];
308 ptr += bytesPerColor;
312 return true;
315 bool parseUncompressedPaletteImage(std::istream &is, const OSGBITMAPINFOHEADER &infoHeader,
316 const RGB colorMap[256], Image* image)
318 unsigned long mask = (1 << infoHeader.biBitCount) - 1;
319 int height;
320 long bytesPerLine;
321 UChar8 *data;
322 if (infoHeader.biHeight >= 0)
324 height = infoHeader.biHeight;
325 bytesPerLine = infoHeader.biWidth * 3;
326 data = image->editData();
328 else
330 height = -infoHeader.biHeight;
331 bytesPerLine = infoHeader.biWidth * -3;
332 data = image->editData() + image->getSize() + bytesPerLine;
335 for (int y = 0; y < height; ++y)
337 int shift = 0;
338 unsigned long bits = 0;
339 UChar8 *ptr = data;
340 for (unsigned int x = 0; x < infoHeader.biWidth; ++x)
342 if (shift == 0)
344 char buffer[4];
345 is.read(buffer, 4);
346 if (is.gcount() != 4)
347 return false;
348 bits = (static_cast<UInt32>(static_cast<UInt8>(buffer[0])) << 24) |
349 (static_cast<UInt32>(static_cast<UInt8>(buffer[1])) << 16) |
350 (static_cast<UInt32>(static_cast<UInt8>(buffer[2])) << 8) |
351 (static_cast<UInt32>(static_cast<UInt8>(buffer[3])) << 0);
352 shift = 32 - infoHeader.biBitCount;
354 else
355 shift -= infoHeader.biBitCount;
356 unsigned long index = (bits >> shift) & mask;
357 *ptr++ = colorMap[index].r;
358 *ptr++ = colorMap[index].g;
359 *ptr++ = colorMap[index].b;
361 data += bytesPerLine;
364 return true;
367 bool parseRLEImage(std::istream &is, const OSGBITMAPINFOHEADER &infoHeader, const RGB colorMap[256], Image* image)
369 unsigned int height;
370 long bytesPerLine;
371 UChar8 *data;
372 if (infoHeader.biHeight >= 0)
374 height = infoHeader.biHeight;
375 bytesPerLine = infoHeader.biWidth * 3;
376 data = image->editData();
378 else
380 height = -infoHeader.biHeight;
381 bytesPerLine = infoHeader.biWidth * -3;
382 data = image->editData() + image->getSize() + bytesPerLine;
385 UChar8 *ptr = data;
386 unsigned int x = 0;
387 for (unsigned int y = 0; y < height; )
389 int c1 = is.get();
390 int c2 = is.get();
391 if ((c1 == EOF) || (c2 == EOF))
392 return false;
393 if (c1 == 0) // Escape
395 switch (c2)
397 case 0: // End of line
398 x = 0;
399 ++y;
400 data += bytesPerLine;
401 ptr = data;
402 break;
403 case 1: // End of bitmap
404 y = height;
405 break;
406 case 2: // Delta
408 int xOffset = is.get();
409 int yOffset = is.get();
410 if ((xOffset == EOF) || (yOffset == EOF))
411 return false;
412 x += xOffset;
413 y += yOffset;
414 if ((x >= infoHeader.biWidth) || (y >= height))
415 return false;
416 data += bytesPerLine * yOffset;
417 ptr += bytesPerLine * yOffset + 3 * xOffset;
419 break;
420 default: // Absolute mode
421 if (infoHeader.biWidth - x < static_cast<unsigned int>(c2))
422 c2 = infoHeader.biWidth - x;
423 x += c2;
424 if (infoHeader.biBitCount == 4)
426 int n = c2;
427 for (int i = 0; i < n; ++i)
429 int index;
430 switch (i & 3)
432 case 0:
433 c1 = is.get();
434 c2 = is.get();
435 if ((c1 == EOF) || (c2 == EOF))
436 return false;
437 index = c1 >> 4;
438 break;
439 case 1:
440 index = c1 & 0xf;
441 break;
442 case 2:
443 index = c2 >> 4;
444 break;
445 case 3:
446 index = c2 & 0xf;
447 break;
448 default:
449 index = 0; // Just to get rid of compiler warnings...
450 break;
452 *ptr++ = colorMap[index].r;
453 *ptr++ = colorMap[index].g;
454 *ptr++ = colorMap[index].b;
457 else
458 for (int i = 0; i < c2; ++i)
460 int index;
461 if ((i & 1) == 0)
463 index = is.get();
464 c1 = is.get();
465 if ((index == EOF) || (c1 == EOF))
466 return false;
468 else
469 index = c1;
470 *ptr++ = colorMap[index].r;
471 *ptr++ = colorMap[index].g;
472 *ptr++ = colorMap[index].b;
474 break;
477 else // Encoded mode
479 if (infoHeader.biWidth - x < static_cast<unsigned int>(c1))
480 c1 = infoHeader.biWidth - x;
481 x += c1;
482 if (infoHeader.biBitCount == 4)
483 for (int i = 0; i < c1; ++i)
485 int index = (i & 1) == 0 ? c2 >> 4 : c2 & 0xf;
486 *ptr++ = colorMap[index].r;
487 *ptr++ = colorMap[index].g;
488 *ptr++ = colorMap[index].b;
490 else
491 for (int i = 0; i < c1; ++i)
493 *ptr++ = colorMap[c2].r;
494 *ptr++ = colorMap[c2].g;
495 *ptr++ = colorMap[c2].b;
500 return true;
503 int calcShift(UInt32 mask)
505 if (mask == 0)
506 return 0;
507 int shift = 0;
508 while (mask > 255)
510 ++shift;
511 mask >>= 1;
513 return shift;
516 bool parseTrueColorImage(std::istream &is, const OSGBITMAPINFOHEADER &infoHeader, Image* image)
518 int redShift = calcShift(infoHeader.redMask);
519 int redScale = infoHeader.redMask == 0 ? 0 : 255 / (infoHeader.redMask >> redShift);
520 int greenShift = calcShift(infoHeader.greenMask);
521 int greenScale = infoHeader.greenMask == 0 ? 0 : 255 / (infoHeader.greenMask >> greenShift);
522 int blueShift = calcShift(infoHeader.blueMask);
523 int blueScale = infoHeader.blueMask == 0 ? 0 : 255 / (infoHeader.blueMask >> blueShift);
524 int alphaShift = calcShift(infoHeader.alphaMask);
525 int alphaScale = infoHeader.alphaMask == 0 ? 0 : 255 / (infoHeader.alphaMask >> alphaShift);
527 int height;
528 long bytesPerLine = infoHeader.biWidth * (infoHeader.alphaMask != 0 ? 4 : 3);
529 UChar8 *data;
530 if (infoHeader.biHeight >= 0)
532 height = infoHeader.biHeight;
533 data = image->editData();
535 else
537 height = -infoHeader.biHeight;
538 bytesPerLine = -bytesPerLine;
539 data = image->editData() + image->getSize() + bytesPerLine;
542 for (int y = 0; y < height; ++y)
544 int shift = 32;
545 unsigned long bits = 0;
546 UChar8 *ptr = data;
547 for (unsigned int x = 0; x < infoHeader.biWidth; ++x)
549 if (shift >= 32)
551 char buffer[4];
552 is.read(buffer, 4);
553 if (is.gcount() != 4)
554 return false;
555 bits = (static_cast<UInt32>(static_cast<UInt8>(buffer[0])) << 0) |
556 (static_cast<UInt32>(static_cast<UInt8>(buffer[1])) << 8) |
557 (static_cast<UInt32>(static_cast<UInt8>(buffer[2])) << 16) |
558 (static_cast<UInt32>(static_cast<UInt8>(buffer[3])) << 24);
559 shift = 0;
561 unsigned long color = bits >> shift;
562 *ptr++ = static_cast<UChar8>(((color & infoHeader.redMask) >> redShift) * redScale);
563 *ptr++ = static_cast<UChar8>(((color & infoHeader.greenMask) >> greenShift) * greenScale);
564 *ptr++ = static_cast<UChar8>(((color & infoHeader.blueMask) >> blueShift) * blueScale);
565 if (infoHeader.alphaMask != 0)
566 *ptr++ = static_cast<UChar8>(((color & infoHeader.alphaMask) >> alphaShift) * alphaScale);
567 shift += infoHeader.biBitCount;
569 data += bytesPerLine;
572 return true;
575 bool parse24bitImage(std::istream &is, const OSGBITMAPINFOHEADER &infoHeader, Image* image)
577 int height;
578 long bytesPerLine;
579 UChar8 *data;
580 if (infoHeader.biHeight >= 0)
582 height = infoHeader.biHeight;
583 bytesPerLine = infoHeader.biWidth * 3;
584 data = image->editData();
586 else
588 height = -infoHeader.biHeight;
589 bytesPerLine = infoHeader.biWidth * -3;
590 data = image->editData() + image->getSize() + bytesPerLine;
592 int padding = (infoHeader.biWidth * 3) & 3;
593 if (padding != 0)
594 padding = 4 - padding;
596 for (int y = 0; y < height; ++y)
598 UChar8 *ptr = data;
599 for (unsigned int x = 0; x < infoHeader.biWidth; ++x)
601 char buffer[3];
602 is.read(buffer, 3);
603 if (is.gcount() != 3)
604 return false;
605 *ptr++ = buffer[2];
606 *ptr++ = buffer[1];
607 *ptr++ = buffer[0];
609 is.ignore(padding);
610 data += bytesPerLine;
613 return true;
616 // -----------------------------------------
617 // write stuff
618 // -----------------------------------------
620 void u_short_int_write(unsigned short int u_short_int_val,
621 std::ostream &os);
623 // fixme
624 bool _bmp_byte_swap = true;
626 void long_int_write ( long int long_int_val, std::ostream &os)
628 long int temp;
629 unsigned short int u_short_int_val_hi;
630 unsigned short int u_short_int_val_lo;
632 temp = long_int_val / 65536;
633 if(temp < 0)
634 temp = temp + 65536;
636 u_short_int_val_hi = static_cast<unsigned short>(temp);
638 temp = long_int_val % 65536;
639 if(temp < 0)
640 temp = temp + 65536;
642 u_short_int_val_lo = static_cast<unsigned short>(temp);
644 if(_bmp_byte_swap)
646 u_short_int_write ( u_short_int_val_lo, os);
647 u_short_int_write ( u_short_int_val_hi, os);
649 else
651 u_short_int_write ( u_short_int_val_hi, os);
652 u_short_int_write ( u_short_int_val_lo, os);
654 return;
657 void u_long_int_write(unsigned long int u_long_int_val,
658 std::ostream &os)
660 unsigned short int u_short_int_val_hi;
661 unsigned short int u_short_int_val_lo;
663 u_short_int_val_hi = static_cast<unsigned short>( u_long_int_val / 65536 );
664 u_short_int_val_lo = static_cast<unsigned short>( u_long_int_val % 65536 );
666 if(_bmp_byte_swap)
668 u_short_int_write ( u_short_int_val_lo, os);
669 u_short_int_write ( u_short_int_val_hi, os);
671 else
673 u_short_int_write ( u_short_int_val_hi, os);
674 u_short_int_write ( u_short_int_val_lo, os);
677 return;
680 void u_short_int_write(unsigned short int u_short_int_val,
681 std::ostream &os)
683 unsigned char chi;
684 unsigned char clo;
686 chi = static_cast<unsigned char>( u_short_int_val / 256 );
687 clo = static_cast<unsigned char>( u_short_int_val % 256 );
689 if(_bmp_byte_swap)
690 os << clo << chi;
691 else
692 os << chi << clo;
694 return;
697 void bmp_header1_write(std::ostream &os, unsigned short int filetype,
698 unsigned long int filesize, unsigned short int reserved1,
699 unsigned short int reserved2, unsigned long int bitmapoffset)
701 u_short_int_write(filetype, os);
702 u_long_int_write(filesize, os);
703 u_short_int_write(reserved1, os);
704 u_short_int_write(reserved2, os);
705 u_long_int_write(bitmapoffset, os);
706 return;
709 void bmp_header2_write(std::ostream &os, unsigned long int size,
710 unsigned long int width, long int height,
711 unsigned short int planes, unsigned short int bitsperpixel,
712 unsigned long int compression, unsigned long int sizeofbitmap,
713 unsigned long int horzresolution, unsigned long int vertresolution,
714 unsigned long int colorsused, unsigned long int colorsimportant)
716 //****************************************************************************
718 // 4 bytes SIZE; Size of this header, in bytes.
719 // 4 bytes WIDTH; Image width, in pixels.
720 // 4 bytes HEIGHT; Image height, in pixels.
721 // (Pos/Neg, origin at bottom, top)
722 // 2 bytes PLANES; Number of color planes (always 1).
723 // 2 bytes BITSPERPIXEL; 1 to 24. 1, 4, 8, 16, 24 or 32.
724 // 4 bytes COMPRESSION; 0, uncompressed; 1, 8 bit RLE;
725 // 2, 4 bit RLE; 3, bitfields.
726 // 4 bytes SIZEOFBITMAP; Size of bitmap in bytes. (0 if uncompressed).
727 // 4 bytes HORZRESOLUTION; Pixels per meter. (Can be zero)
728 // 4 bytes VERTRESOLUTION; Pixels per meter. (Can be zero)
729 // 4 bytes COLORSUSED; Number of colors in palette. (Can be zero).
730 // 4 bytes COLORSIMPORTANT. Minimum number of important colors. (Can be zero).
732 // Parameters:
734 // Input, ofstream &FILE_OUT, a reference to the output file.
736 // Input, unsigned long int SIZE, the size of this header in bytes.
738 // Input, unsigned long int WIDTH, the X dimensions of the image.
740 // Input, long int HEIGHT, the Y dimensions of the image.
742 // Input, unsigned short int PLANES, the number of color planes.
744 // Input, unsigned short int BITSPERPIXEL, color bits per pixel.
746 // Input, unsigned long int COMPRESSION, the compression option.
748 // Input, unsigned long int SIZEOFBITMAP, the size of the bitmap.
750 // Input, unsigned long int HORZRESOLUTION, the horizontal resolution.
752 // Input, unsigned long int VERTRESOLUTION, the vertical resolution.
754 // Input, unsigned long int COLORSUSED, the number of colors in the palette.
756 // Input, unsigned long int COLORSIMPORTANT, the minimum number of colors.
759 u_long_int_write(size, os);
760 u_long_int_write(width, os);
761 long_int_write(height, os);
762 u_short_int_write(planes, os);
763 u_short_int_write(bitsperpixel, os);
764 u_long_int_write(compression, os);
765 u_long_int_write(sizeofbitmap, os);
766 u_long_int_write(horzresolution, os);
767 u_long_int_write(vertresolution, os);
768 u_long_int_write(colorsused, os);
769 u_long_int_write(colorsimportant, os);
770 return;
773 void bmp_24_data_write(std::ostream &os, unsigned long int width,
774 long int height, const unsigned char *data)
776 int padding;
778 // Set the padding.
779 padding = ( 4 - ( ( 3 * width ) % 4 ) ) % 4;
781 for(long j = 0; j < abs ( height ); ++j)
783 for(unsigned long i = 0; i < width; ++i)
785 os << *(data + 2);
786 os << *(data + 1);
787 os << *(data + 0);
788 data += 3;
791 for(int i = 0; i < padding; ++i)
793 os << 0;
796 return;
799 // -----------
801 // Static Class Variable implementations:
802 const Char8 *suffixArray[] =
804 "bmp", "dib", "rle"
807 } // namespace
809 BMPImageFileType BMPImageFileType:: _the("image/bmp",
810 suffixArray,
811 sizeof(suffixArray),
812 (OSG_READ_SUPPORTED |
813 OSG_WRITE_SUPPORTED));
816 //-------------------------------------------------------------------------
817 /*! Tries to fill the image object with the data read from
818 the given fileName. Returns true on success.
821 bool BMPImageFileType::read( Image *pImage,
822 std::istream &is,
823 const std::string &mimetype)
825 // Parse bitmap file header
826 OSGBITMAPFILEHEADER fileHeader;
827 if (readBitmapFileHeader(is, fileHeader) == false)
828 return false;
830 // Parse bitmap info header
831 OSGBITMAPINFOHEADER infoHeader;
832 if (readBitmapInfoHeader(is, infoHeader) == false)
833 return false;
835 // Parse color map
836 RGB colorMap[256];
837 if (readColorMap(is, fileHeader, infoHeader, colorMap) == false)
838 return false;
840 // Parse the image data
841 UInt32 pixelFormat = infoHeader.alphaMask != 0 ? Image::OSG_RGBA_PF: Image::OSG_RGB_PF;
842 Int32 height = infoHeader.biHeight >= 0 ? infoHeader.biHeight : -infoHeader.biHeight;
843 pImage->set(pixelFormat, infoHeader.biWidth, height);
844 switch (infoHeader.biBitCount)
846 case 1:
847 case 4:
848 case 8:
849 if (infoHeader.biCompression == 0 /*BI_RGB*/)
851 if (parseUncompressedPaletteImage(is, infoHeader, colorMap, pImage) == false)
852 return false;
854 else
856 if (parseRLEImage(is, infoHeader, colorMap, pImage) == false)
857 return false;
859 break;
860 case 16:
861 case 32:
862 if (parseTrueColorImage(is, infoHeader, pImage) == false)
863 return false;
864 break;
865 case 24:
866 if (parse24bitImage(is, infoHeader, pImage) == false)
867 return false;
868 break;
869 default:
870 return false;
874 return true;
877 //-------------------------------------------------------------------------
878 /*! Tries to write the image object to the given output stream.
879 Returns true on success.
882 bool BMPImageFileType::write(const Image *pImage,
883 std::ostream &os,
884 const std::string &mimetype)
886 if(!pImage)
887 return false;
889 int bpp = pImage->getBpp();
890 if(bpp != 3)
892 FWARNING(("Writing of bmp files is only supported for 24 bit RGB images!\n"));
893 return false;
896 if (!os.good())
897 return false;
899 int width = pImage->getWidth();
900 int height = pImage->getHeight();
901 const unsigned char *data =
902 static_cast<const unsigned char *>(pImage->getData());
904 unsigned long int bitmapoffset;
905 unsigned short int bitsperpixel;
906 unsigned long int colorsimportant;
907 unsigned long int colorsused;
908 unsigned long int compression;
909 unsigned long int filesize;
910 unsigned short int filetype;
911 unsigned long int horzresolution;
912 int padding;
913 unsigned short int planes;
914 unsigned short int reserved1 = 0;
915 unsigned short int reserved2 = 0;
916 unsigned long int size = 40;
917 unsigned long int sizeofbitmap;
918 unsigned long int vertresolution;
920 // Write header 1.
921 if(_bmp_byte_swap)
922 filetype = 'M' * 256 + 'B';
923 else
924 filetype = 'B' * 256 + 'M';
926 // Determine the padding needed when WIDTH is not a multiple of 4.
927 padding = ( 4 - ( ( 3 * width ) % 4 ) ) % 4;
929 filesize = 54 + ( ( 3 * width ) + padding ) * abs ( height );
930 bitmapoffset = 54;
932 bmp_header1_write(os, filetype, filesize, reserved1,
933 reserved2, bitmapoffset );
935 // Write header 2.
937 planes = 1;
938 bitsperpixel = 24;
939 compression = 0;
940 sizeofbitmap = 0;
941 horzresolution = 0;
942 vertresolution = 0;
943 colorsused = 0;
944 colorsimportant = 0;
946 bmp_header2_write(os, size, width, height, planes, bitsperpixel,
947 compression, sizeofbitmap, horzresolution, vertresolution,
948 colorsused, colorsimportant);
950 // Write the data.
951 bmp_24_data_write(os, width, height, data);
953 return true;
956 //-------------------------------------------------------------------------
958 Tries to determine the mime type of the data provided by an input stream
959 by searching for magic bytes. Returns the mime type or an empty string
960 when the function could not determine the mime type.
963 std::string BMPImageFileType::determineMimetypeFromStream(std::istream &is)
965 char filecode[2];
967 is.read(filecode, 2);
968 is.seekg(-2, std::ios::cur);
970 return strncmp(filecode, "BM", 2) == 0 ?
971 std::string(getMimeType()) : std::string();
974 //-------------------------------------------------------------------------
975 /*! Constructor used for the singleton object
978 BMPImageFileType::BMPImageFileType(const Char8 *mimeType,
979 const Char8 *suffixArray[],
980 UInt16 suffixByteCount,
981 UInt32 flags) :
982 Inherited(mimeType,
983 suffixArray,
984 suffixByteCount,
985 flags )
989 //-------------------------------------------------------------------------
990 /*! Destructor
993 BMPImageFileType::~BMPImageFileType(void)
997 OSG_END_NAMESPACE