- int rshift = 0, gshift = 0, bshift = 0;
- wxUint8 aByte;
- wxUint16 aWord;
- wxInt32 dbuf[4], aDword,
- rmask = 0, gmask = 0, bmask = 0;
- wxInt8 bbuf[4];
- struct _cmap {
- unsigned char r, g, b;
- } *cmap = NULL;
-
- off_t start_offset = stream.TellI();
-
- image->Destroy();
-
- /*
- * Read the BMP header
- */
-
- stream.Read( &bbuf, 2 );
- stream.Read( dbuf, 4 * 4 );
-
- wxInt32 size = wxINT32_SWAP_ON_BE( dbuf[0] );
- wxInt32 offset = wxINT32_SWAP_ON_BE( dbuf[2] );
-
- stream.Read(dbuf, 4 * 2);
- int width = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
- int height = (int)wxINT32_SWAP_ON_BE( dbuf[1] );
- if (width > 32767)
- {
- wxLogError( _T("Image width > 32767 pixels for file.") );
- return FALSE;
- }
- if (height > 32767)
- {
- wxLogError( _T("Image height > 32767 pixels for file.") );
- return FALSE;
- }
-
- stream.Read( &aWord, 2 );
-/*
- TODO
- int planes = (int)wxUINT16_SWAP_ON_BE( aWord );
-*/
- stream.Read( &aWord, 2 );
- int bpp = (int)wxUINT16_SWAP_ON_BE( aWord );
- if (bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32)
- {
- wxLogError( _T("unknown bitdepth in file.") );
- return FALSE;
- }
-
- stream.Read( dbuf, 4 * 4 );
- int comp = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
- if (comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && comp != BI_BITFIELDS)
- {
- wxLogError( _T("unknown encoding in Windows BMP file.") );
- return FALSE;
- }
-
- stream.Read( dbuf, 4 * 2 );
- int ncolors = (int)wxINT32_SWAP_ON_BE( dbuf[0] );
- if (ncolors == 0)
- ncolors = 1 << bpp;
- /* some more sanity checks */
- if (((comp == BI_RLE4) && (bpp != 4)) ||
- ((comp == BI_RLE8) && (bpp != 8)) ||
- ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32)))
- {
- wxLogError( _T("encoding of BMP doesn't match bitdepth.") );
- return FALSE;
- }
- if (bpp < 16)
- {
- cmap = (struct _cmap *)malloc(sizeof(struct _cmap) * ncolors);
- if (!cmap)
- {
- wxLogError( _T("Cannot allocate RAM for color map in BMP file.") );
- return FALSE;
- }
- }
- else
- cmap = NULL;
-
- image->Create( width, height );
- unsigned char *ptr = image->GetData();
- if (!ptr)
- {
- wxLogError( _T("Cannot allocate RAM for RGB data in file.") );
- if (cmap)
- free(cmap);
- return FALSE;
- }
-
- /*
- * Reading the palette, if it exists.
- */
- if (bpp < 16 && ncolors != 0)
- {
- for (int j = 0; j < ncolors; j++)
- {
- stream.Read( bbuf, 4 );
- cmap[j].b = bbuf[0];
- cmap[j].g = bbuf[1];
- cmap[j].r = bbuf[2];
- }
- }
- else if (bpp == 16 || bpp == 32)
- {
- if (comp == BI_BITFIELDS)
- {
- int bit = 0;
- stream.Read( dbuf, 4 * 3 );
- bmask = wxINT32_SWAP_ON_BE( dbuf[0] );
- gmask = wxINT32_SWAP_ON_BE( dbuf[1] );
- rmask = wxINT32_SWAP_ON_BE( dbuf[2] );
- /* find shift amount.. ugly, but i can't think of a better way */
- for (bit = 0; bit < bpp; bit++)
- {
- if (bmask & (1 << bit))
- bshift = bit;
- if (gmask & (1 << bit))
- gshift = bit;
- if (rmask & (1 << bit))
- rshift = bit;
- }
- }
- else if (bpp == 16)
- {
- rmask = 0x7C00;
- gmask = 0x03E0;
- bmask = 0x001F;
- rshift = 10;
- gshift = 5;
- bshift = 0;
- }
- else if (bpp == 32)
- {
- rmask = 0x00FF0000;
- gmask = 0x0000FF00;
- bmask = 0x000000FF;
- rshift = 16;
- gshift = 8;
- bshift = 0;
- }
- }
-
- /*
- * Reading the image data
- */
- stream.SeekI( start_offset + offset );
- unsigned char *data = ptr;
-
- /* set the whole image to the background color */
- if (bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8))
- {
- for (int i = 0; i < width * height; i++)
- {
- *ptr++ = cmap[0].r;
- *ptr++ = cmap[0].g;
- *ptr++ = cmap[0].b;
- }
- ptr = data;
- }
-
- int line = 0;
- int column = 0;
- int linesize = ((width * bpp + 31) / 32) * 4;
-
- /* BMPs are stored upside down */
- for (line = (height - 1); line >= 0; line--)
- {
- int linepos = 0;
- for (column = 0; column < width;)
- {
- if (bpp < 16)
- {
- int index = 0;
- linepos++;
- aByte = stream.GetC();
- if (bpp == 1)
- {
- int bit = 0;
- for (bit = 0; bit < 8; bit++)
- {
- index = ((aByte & (0x80 >> bit)) ? 1 : 0);
- ptr[poffset] = cmap[index].r;
- ptr[poffset + 1] = cmap[index].g;
- ptr[poffset + 2] = cmap[index].b;
- column++;
- }
- }
- else if (bpp == 4)
- {
- if (comp == BI_RLE4)
- {
- wxLogError( _T("Can't deal with 4bit encoded yet.") );
- image->Destroy();
- free(cmap);
- return FALSE;
- }
- else
- {
- int nibble = 0;
- for (nibble = 0; nibble < 2; nibble++)
- {
- index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4));
- if (index >= 16)
- index = 15;
- ptr[poffset] = cmap[index].r;
- ptr[poffset + 1] = cmap[index].g;
- ptr[poffset + 2] = cmap[index].b;
- column++;
- }
- }
- }
- else if (bpp == 8)
- {
- if (comp == BI_RLE8)
- {
- unsigned char first;
- first = aByte;
- aByte = stream.GetC();
- if (first == 0)
- {
- if (aByte == 0)
- {
- /* column = width; */
- }
- else if (aByte == 1)
- {
- column = width;
- line = -1;
- }
- else if (aByte == 2)
- {
- aByte = stream.GetC();
- column += aByte;
- linepos = column * bpp / 8;
- aByte = stream.GetC();
- line += aByte;
- }
- else
- {
- int absolute = aByte;
- for (int k = 0; k < absolute; k++)
- {
- linepos++;
- aByte = stream.GetC();
- ptr[poffset ] = cmap[aByte].r;
- ptr[poffset + 1] = cmap[aByte].g;
- ptr[poffset + 2] = cmap[aByte].b;
- column++;
- }
- if (absolute & 0x01)
- aByte = stream.GetC();
- }
- }
- else
- {
- for (int l = 0; l < first; l++)
- {
- ptr[poffset ] = cmap[aByte].r;
- ptr[poffset + 1] = cmap[aByte].g;
- ptr[poffset + 2] = cmap[aByte].b;
- column++;
- linepos++;
- }
- }
- }
- else
- {
- ptr[poffset ] = cmap[aByte].r;
- ptr[poffset + 1] = cmap[aByte].g;
- ptr[poffset + 2] = cmap[aByte].b;
- column++;
- linepos += size;
- }
- }
- }
- else if (bpp == 24)
- {
- stream.Read( &bbuf, 3 );
- linepos += 3;
- ptr[poffset ] = (unsigned char)bbuf[2];
- ptr[poffset + 1] = (unsigned char)bbuf[1];
- ptr[poffset + 2] = (unsigned char)bbuf[0];
- column++;
- }
- else if (bpp == 16)
- {
- unsigned char temp;
- stream.Read( &aWord, 2 );
- aWord = wxUINT16_SWAP_ON_BE( aWord );
- linepos += 2;
- temp = (aWord & rmask) >> rshift;
- ptr[poffset] = temp;
- temp = (aWord & gmask) >> gshift;
- ptr[poffset + 1] = temp;
- temp = (aWord & bmask) >> gshift;
- ptr[poffset + 2] = temp;
- column++;
- }
- else
- {
- unsigned char temp;
- stream.Read( &aDword, 4 );
- aDword = wxINT32_SWAP_ON_BE( aDword );
- linepos += 4;
- temp = (aDword & rmask) >> rshift;
- ptr[poffset] = temp;
- temp = (aDword & gmask) >> gshift;
- ptr[poffset + 1] = temp;
- temp = (aDword & bmask) >> bshift;
- ptr[poffset + 2] = temp;
- column++;
- }
- }
- while ((linepos < linesize) && (comp != 1) && (comp != 2))
- {
- stream.Read( &aByte, 1 );
- linepos += 1;
- if (stream.LastError() != wxStream_NOERROR)
- break;
- }
- }
- if (cmap)
- free(cmap);
-
- image->SetMask( FALSE );
-
- return TRUE;