📄 bmpdecoder.cpp
字号:
pixel->green = color_table [color].rgbGreen ;
pixel->blue = color_table [color].rgbBlue ;
}
}
}
return ;
}
void BmpDecoder::read16BitData (std::istream &strm ,
int height, int width,
BitmapImage &image,
unsigned long redmask, unsigned long greenmask,
unsigned long bluemask, unsigned long alphamask)
{
unsigned long allbits = redmask | greenmask | bluemask | alphamask ;
if ((allbits & redmask) != redmask || (allbits & greenmask) != greenmask
|| (allbits & bluemask) != bluemask || (allbits & alphamask) != alphamask)
{
throw BmpError ("Overlapping component mask") ;
}
UBYTE4 redsize, redoffset ;
UBYTE4 greensize, greenoffset ;
UBYTE4 bluesize, blueoffset ;
UBYTE4 alphasize, alphaoffset ;
FindMask (redmask, redoffset, redsize) ;
FindMask (greenmask, greenoffset, greensize) ;
FindMask (bluemask, blueoffset, bluesize) ;
FindMask (alphamask, alphaoffset, alphasize) ;
unsigned int physicalrowsize = (sizeof (UBYTE2) * width + 0x3) & ~0x3 ;
Buffer<UBYTE2> buffer (physicalrowsize / sizeof (UBYTE2)) ;
// Images with positive heights are stored bottom up. Images with
// negative height are stored top down.
if (height > 0)
{
for (unsigned int ii = 0 ; ii < height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
// The pixel rows are stored in reverse order.
unsigned int index = (height - ii - 1) * width ;
BitmapImage::Pixel *pixel = &image [index] ;
for (unsigned int jj = 0 ; jj < width ; ++ jj, ++ pixel)
{
UBYTE2 color = LittleEndianToSystem (buffer [jj]) ;
pixel->red = ((color & redmask) >> (redoffset + redsize - 1)) & 0xFFU ;
pixel->green = ((color & greenmask) >> (greenoffset + greensize - 1)) & 0xFFU ;
pixel->blue = ((color & bluemask) >> (blueoffset + bluesize - 1)) & 0xFFU ;
pixel->alpha = ((color & alphamask) >> (alphaoffset + alphasize - 1)) & 0xFFU ;
}
}
}
else
{
BitmapImage::Pixel *pixel = &image [0] ;
for (unsigned int ii = 0 ; ii < - height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
for (unsigned int jj = 0 ; jj < width ; ++ jj, ++ pixel)
{
UBYTE2 color = LittleEndianToSystem (buffer [jj]) ;
pixel->red = ((color & redmask) >> (redoffset + redsize - 1)) & 0xFFU ;
pixel->green = ((color & greenmask) >> (greenoffset + greensize - 1)) & 0xFFU ;
pixel->blue = ((color & bluemask) >> (blueoffset + bluesize - 1)) & 0xFFU ;
pixel->alpha = ((color & alphamask) >> (alphaoffset + alphasize - 1)) & 0xFFU ;
}
}
}
return ;
}
void BmpDecoder::read24BitData (std::istream &strm,
int height, int width,
BitmapImage &image)
{
// This is is rowwidth rounded up to the nearest 4 bytes.
unsigned int physicalrowsize = (3 * width + 0x3) & ~0x3 ;
Buffer<UBYTE1> buffer (physicalrowsize) ;
// Images with positive heights are stored bottom up. Images with
// negative height are stored top down.
if (height > 0)
{
for (unsigned int ii = 0 ; ii < height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
// The pixel rows are stored in reverse order.
unsigned int index = (height - ii - 1) * width ;
BitmapImage::Pixel *pixel = &image [index] ;
for (unsigned int jj = 0, kk = 0 ; jj < width ; ++ jj, ++ pixel)
{
pixel->blue = buffer [kk] ; ++ kk ;
pixel->green = buffer [kk] ; ++ kk ;
pixel->red = buffer [kk] ; ++ kk ;
}
}
}
else
{
BitmapImage::Pixel *pixel = &image [0] ;
for (unsigned int ii = 0 ; ii < - height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
for (unsigned int jj = 0, kk = 0 ; jj < width ; ++ jj, ++ pixel)
{
pixel->blue = buffer [kk] ; ++ kk ;
pixel->green = buffer [kk] ; ++ kk ;
pixel->red = buffer [kk] ; ++ kk ;
}
}
}
return ;
}
void BmpDecoder::read32BitData (std::istream &strm,
int height, int width,
BitmapImage &image,
unsigned long redmask,
unsigned long greenmask,
unsigned long bluemask,
unsigned long alphamask)
{
unsigned long allbits = redmask | greenmask | bluemask | alphamask ;
if ((allbits & redmask) != redmask || (allbits & greenmask) != greenmask
|| (allbits & bluemask) != bluemask || (allbits & alphamask) != alphamask)
{
throw BmpError ("Overlapping component mask") ;
}
UBYTE4 redsize, redoffset ;
UBYTE4 greensize, greenoffset ;
UBYTE4 bluesize, blueoffset ;
UBYTE4 alphasize, alphaoffset ;
FindMask (redmask, redoffset, redsize) ;
FindMask (greenmask, greenoffset, greensize) ;
FindMask (bluemask, blueoffset, bluesize) ;
FindMask (alphamask, alphaoffset, alphasize) ;
unsigned int physicalrowsize = sizeof (UBYTE4) * width ;
Buffer<UBYTE4> buffer (width) ;
// Images with positive heights are stored bottom up. Images with
// negative height are stored top down.
if (height > 0)
{
for (unsigned int ii = 0 ; ii < height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
// The pixel rows are stored in reverse order.
unsigned int index = (height - ii - 1) * width ;
BitmapImage::Pixel *pixel = &image [index] ;
for (unsigned int jj = 0 ; jj < width ; ++ jj, ++ pixel)
{
UBYTE4 color = LittleEndianToSystem (buffer [jj]) ;
pixel->red = ((color & redmask) >> (redoffset + redsize - CHAR_BIT)) & 0xFFU ;
pixel->green = ((color & greenmask) >> (greenoffset + greensize - CHAR_BIT)) & 0xFFU ;
pixel->blue = ((color & bluemask) >> (blueoffset + bluesize - CHAR_BIT)) & 0xFFU ;
pixel->alpha = ((color & alphamask) >> (alphaoffset + alphasize - CHAR_BIT)) & 0xFFU ;
}
}
}
else
{
BitmapImage::Pixel *pixel = &image [0] ;
for (unsigned int ii = 0 ; ii < - height ; ++ ii)
{
callProgressFunction (ii * 100 / height) ;
strm.read (reinterpret_cast<char *>(&buffer [0]), physicalrowsize) ;
if (strm.gcount () != physicalrowsize)
throw BmpError ("Premature End of Stream") ;
for (unsigned int jj = 0 ; jj < width ; ++ jj, ++ pixel)
{
UBYTE4 color = LittleEndianToSystem (buffer [jj]) ;
pixel->red = ((color & redmask) >> (redoffset + redsize - CHAR_BIT)) & 0xFFU ;
pixel->green = ((color & greenmask) >> (greenoffset + greensize - CHAR_BIT)) & 0xFFU ;
pixel->blue = ((color & bluemask) >> (blueoffset + bluesize - CHAR_BIT)) & 0xFFU ;
pixel->alpha = ((color & alphamask) >> (alphaoffset + alphasize - CHAR_BIT)) & 0xFFU ;
}
}
}
return ;
}
unsigned int BmpDecoder::readOs2ColorTable (std::istream &strm,
unsigned int colorcount)
{
for (unsigned int ii = 0 ; ii < colorcount ; ++ ii)
{
RGBTRIPLE color ;
strm.read (reinterpret_cast<char *>(&color), sizeof (color)) ;
color_table [ii].rgbRed = color.rgbtRed ;
color_table [ii].rgbBlue = color.rgbtBlue ;
color_table [ii].rgbGreen = color.rgbtGreen ;
}
return colorcount * sizeof (RGBTRIPLE) ;
}
unsigned int BmpDecoder::readColorTable (std::istream &strm,
unsigned int colorcount)
{
unsigned int bytes = sizeof (RGBQUAD) * colorcount ;
strm.read (reinterpret_cast<char *>(&color_table [0]), bytes) ;
return bytes ;
}
void BmpDecoder::readRle4 (std::istream &strm , int height, int width, BitmapImage &image)
{
if (height < 0)
throw BmpError ("Negative height not allowed in an RLE image") ;
// The mechanism here is the same as for BI_RLE8 with two
// exceptions. Here we are dealing with 4-bit nibbles rather
// than whole bytes. This results in some extra work. In
// addition, the coding of runs includes two color values.
unsigned int row = - (height + 1) ;
BitmapImage::Pixel *pixel = &image [row * width] ;
unsigned int col = 0 ;
bool done = false ;
while (! strm.eof () && ! done)
{
callProgressFunction ((height - row - 1) * 100 / height) ;
struct
{
UBYTE1 count ;
UBYTE1 command ;
} opcode ;
strm.read (reinterpret_cast<char *>(&opcode), sizeof (opcode)) ;
if (opcode.count == 0)
{
switch (opcode.command)
{
case 0: // Advance to next pixel row
-- row ;
pixel = &image [row * width] ;
col = 0 ;
break ;
case 1: // Image complete
done = true ;
break ;
case 2: // Move to relative location the image.
{
UBYTE1 dx ;
UBYTE1 dy ;
strm.read (reinterpret_cast<char *>(&dx), sizeof (dx)) ;
strm.read (reinterpret_cast<char *>(&dy), sizeof (dy)) ;
col += dx ;
row -= dy ;
pixel = &image [row * width] ;
}
break ;
default:
{
UBYTE1 data ;
UBYTE1 hi ;
UBYTE1 lo ;
if (row >= height || col + opcode.command > width)
throw BmpError ("Corrupt Data") ;
for (unsigned int ii = 0 ; ii < opcode.command ; ++ ii)
{
if ((ii & 1) == 0)
{
strm.read (reinterpret_cast<char *>(&data), sizeof (data)) ;
lo = data & 0xF ;
hi = (data & 0xF0) >> 4 ;
}
if ((ii & 1) == 0)
{
pixel [col].red = color_table [hi].rgbRed ;
pixel [col].green = color_table [hi].rgbGreen ;
pixel [col].blue = color_table [hi].rgbBlue ;
}
else
{
pixel [col].red = color_table [lo].rgbRed ;
pixel [col].green = color_table [lo].rgbGreen ;
pixel [col].blue = color_table [lo].rgbBlue ;
}
++ col ;
}
// If the number of bytes used in this instruction
// is odd then there is a padding byte.
switch (opcode.command & 0x3)
{
case 1: case 2:
strm.read (reinterpret_cast<char *>(&data), sizeof (data)) ;
break ;
}
}
break ;
}
}
else
{
// Process a run of the same color value pairs.
UBYTE1 hi = opcode.command >> 4 ;
UBYTE1 lo = opcode.command & 0xF ;
if (row >= height || col + opcode.count > width)
throw BmpError ("Corrupt Data") ;
for (unsigned int ii = 0 ; ii < opcode.count ; ++ ii)
{
if ((ii & 1) == 0)
{
pixel [col].red = color_table [hi].rgbRed ;
pixel [col].green = color_table [hi].rgbGreen ;
pixel [col].blue = color_table [hi].rgbBlue ;
}
else
{
pixel [col].red = color_table [lo].rgbRed ;
pixel [col].green = color_table [lo].rgbGreen ;
pixel [col].blue = color_table [lo].rgbBlue ;
}
++ col ;
}
}
}
if (! done)
throw BmpError ("Corrupt Data") ;
return ;
}
void BmpDecoder::readRle8 (std::istream &strm , int height, int width, BitmapImage &image)
{
if (height < 0)
throw BmpError ("Negative height not allowed in an RLE image") ;
unsigned int row = - (height + 1) ; // Current row
unsigned int col = 0 ; // Current column
BitmapImage::Pixel *pixel = &image [row * width] ;
bool done = false ;
while (! strm.eof () && ! done)
{
callProgressFunction ((height - row - 1) * 100 / height) ;
// Structure for reading RLE commands.
struct
{
UBYTE1 count ;
UBYTE1 command ;
} opcode ;
strm.read (reinterpret_cast<char *>(&opcode), sizeof (opcode)) ;
if (opcode.count == 0)
{
// A byte count of zero means that this is a special
// instruction.
switch (opcode.command)
{
case 0: // 0 => Move to next row
-- row ;
col = 0 ;
pixel = &image [row * width] ;
break ;
case 1: // 1 => Image is finished
done = true ;
break ;
case 2: // 2 => Move to a new relative position.
{
// Read the relative position.
UBYTE1 dx ;
UBYTE1 dy ;
strm.read (reinterpret_cast<char *>(&dx), sizeof (dx)) ;
strm.read (reinterpret_cast<char *>(&dy), sizeof (dy)) ;
col += dx ;
row -= dy ;
pixel = &image [row * width] ;
}
break ;
default:
{
// Store absolute data. The command code is the
// number of absolute bytes to store.
if (row >= height || col + opcode.command > width)
throw BmpError ("Corrupt Data") ;
UBYTE1 data ;
for (unsigned int ii = 0 ; ii < opcode.command ; ++ ii)
{
strm.read (reinterpret_cast<char *>(&data), sizeof (data)) ;
pixel [col].red = color_table [data].rgbRed ;
pixel [col].green = color_table [data].rgbGreen ;
pixel [col].blue = color_table [data].rgbBlue ;
++ col ;
}
// An odd number of bytes is followed by a pad byte.
if ((opcode.command & 1) != 0)
strm.read (reinterpret_cast<char *>(&data), sizeof (data)) ;
}
break ;
}
}
else
{
// Store a run of the same color value.
if (row >= height || col + opcode.count > width)
throw BmpError ("Corrupt Data") ;
for (unsigned int ii = 0 ; ii < opcode.count ; ++ ii)
{
pixel [col].red = color_table [opcode.command].rgbRed ;
pixel [col].green = color_table [opcode.command].rgbGreen ;
pixel [col].blue = color_table [opcode.command].rgbBlue ;
++ col ;
}
}
}
if (! done)
throw BmpError ("Corrupt Data") ;
return ;
}
} // End Namespace Colosseum
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -