⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bmpdecoder.cpp

📁 Jpeg编解码器的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) 1997,1998, 1999 Colosseum Builders, Inc.
// All rights reserved.
//
// Colosseum Builders, Inc. makes no warranty, expressed or implied
// with regards to this software. It is provided as is.
//
// See the README.TXT file that came with this software for restrictions
// on the use and redistribution of this file or send E-mail to
// info@colosseumbuilders.com
//

//
//  BMP Decoder Library.
//
//  Title:   BmpDecoder Class Implementation
//
//  Author:  John M. Miano (miano@colosseumbuilders.com)
//
//  Date:    April 15, 1999
//
//  Version: 3
//
//  Description:
//
//    Windows BMP Encoder
//
//  Revision History:
//

#include <windows.h>

#include <fstream>
#include <climits>

#include "bmpdecoder.h"
#include "buffer.h"

using namespace std ;

namespace
{
//
//  This function takes a contiguous bit mask and determines the
//  offset and size of the bit mask.
//
void FindMask (UBYTE4 mask, UBYTE4 &offset, UBYTE4 &size)
{
  offset = 0 ;
  while ((mask & (1 << offset)) == 0 && offset < 32)
    ++ offset ;
  size = 0 ;
  while (offset + size < 32 && (mask & (1 << (offset + size))) != 0)
    ++ size ;
  return ;
}

}

namespace Colosseum
{

//
//  Description:
//
//    Class default constructor
//

//
//  Description:
//
//    Default Constructor
//
BmpDecoder::BmpDecoder ()
{
  return ;
}

//
//  Description:
//
//    Class Copy Constructor
//
BmpDecoder::BmpDecoder (const BmpDecoder &source)
: BitmapImageDecoder (source)
{
  return ;
}

//
//  Description:
//
//    Class Destructor
//
BmpDecoder::~BmpDecoder ()
{
  return ;
}

//
//  Description:
//
//    Assignment operator.
//
//  Parameters:
//   source: The object to copy
//
BmpDecoder &BmpDecoder::operator=(const BmpDecoder &source)
{
  BitmapImageDecoder::operator=(source) ;
  return *this ;
}


//
//  Description:
//
//    This function reads an image from a Windows BMP stream.
//
//  Parameters:
//    strm: The input stream
//    image: The image to be read
//
void BmpDecoder::readImage (std::istream &strm, BitmapImage &image)
{
  callProgressFunction (0) ;

  // We need this because MSVC++ does not follow standard scoping
  // rules in for statements.
  unsigned int ii ;

  unsigned int bytesread = 0 ;

  BITMAPFILEHEADER fileheader ;
  strm.read (reinterpret_cast<char *>(&fileheader), sizeof (fileheader)) ;
  if (strm.gcount () != sizeof(fileheader))
    throw BmpError ("Premature End of Stream") ;
  bytesread += sizeof (fileheader) ;

  const UBYTE2 signature = 'B' | ('M' << CHAR_BIT) ;
  if (fileheader.bfType != signature)
    throw BmpError ("Not a BMP Image") ;

  // The header can come in one of two flavors.  They both
  // begin with a 4-byte headersize.

  UBYTE4 headersize ;
  strm.read (reinterpret_cast<char *>(&headersize), sizeof (headersize)) ;
  if (strm.gcount () != sizeof(headersize))
    throw BmpError ("Premature End of Stream") ;

  headersize = LittleEndianToSystem (headersize) ;
  Buffer<UBYTE1> headerbuffer (headersize) ;
  strm.read (reinterpret_cast<char*>(&headerbuffer [sizeof (headersize)]),
             headersize - sizeof (headersize)) ;
  bytesread += headersize ;

  unsigned long width ;
  long height ;
  unsigned int bitcount ;
  unsigned int compression ;
  color_table_size = 0 ;
  if (headersize == sizeof (BITMAPCOREHEADER))
  {
    BITMAPCOREHEADER header = reinterpret_cast<BITMAPCOREHEADER&>(headerbuffer [0]) ;
    width = LittleEndianToSystem (header.bcWidth) ;
    height = LittleEndianToSystem (header.bcHeight) ;
    bitcount = LittleEndianToSystem (header.bcBitCount) ;

    color_table_size = 1 << bitcount ;
    bytesread += readOs2ColorTable (strm, color_table_size) ;
    compression = BI_RGB ;
  }
  else if (headersize >= sizeof (BITMAPINFOHEADER))
  {
    BITMAPINFOHEADER &header = reinterpret_cast<BITMAPINFOHEADER&>(headerbuffer [0]) ;
    compression = LittleEndianToSystem (static_cast<UBYTE4>(header.biCompression)) ;

    width = LittleEndianToSystem (static_cast<UBYTE4>(header.biWidth)) ;
    height = LittleEndianToSystem (static_cast<UBYTE4>(header.biHeight)) ;
    bitcount = LittleEndianToSystem (static_cast<UBYTE4>(header.biBitCount)) ;

    color_table_size = LittleEndianToSystem (static_cast<UBYTE4>(header.biClrUsed)) ;
    if (color_table_size == 0 && bitcount  < 16)
    {
      // If the colors used field is non-zero, it gives the size of the
      // color table. Otherwise, the number of bits per pixel gives the size.
      color_table_size = 1 << bitcount ;
    }

    // Validate Compression
    switch (bitcount)
    {
    case 1:
      if (compression != BI_RGB)
        throw BmpError ("Unsupported Compression") ;
      break ;
    case 4:
      if (compression != BI_RGB && compression != BI_RLE4)
        throw BmpError ("Unsupported Compression") ;
      break ;
    case 8:
      if (compression != BI_RGB &&  compression != BI_RLE8)
        throw BmpError ("Unsupported Compression") ;
      break ;
    case 24:
      if (compression != BI_RGB)
        throw BmpError ("Unsupported Compression") ;
      break ;
    case 16: case 32:
      if (compression != BI_RGB && compression != BI_BITFIELDS)
        throw BmpError ("Unsupported Compression") ;
      break ;
    default:
      throw BmpError ("Unsupported bit count") ;
    }
    if (color_table_size != 0)
      bytesread += readColorTable (strm, color_table_size) ;
  }
  else
  {
    throw BmpError ("Invalid header size") ;
  }

  // Allocate storage for the image.
  if (height >= 0)
    image.setSize (width, height) ;
  else
    image.setSize (width, -height) ;

  // It is poss ible to have a file where the image data does not
  // immediately follow the color map (or headers). If there is
  // padding we skip over it.

  if (bytesread > fileheader.bfOffBits)
    throw BmpError ("Corrupt File") ;

  for (ii = bytesread ; ii < fileheader.bfOffBits ; ++ ii)
  {
    UBYTE1 data ;
    strm.read (reinterpret_cast<char *>(&data), sizeof (data)) ;
  }

  switch (bitcount)
  {
  case 1: case 2: case 4:
    if (compression == BI_RGB)
      readFractionalByteData (strm, bitcount, height, width, image) ;
    else
      readRle4 (strm, height, width, image) ;
    break ;
  case 8:
    if (compression == BI_RGB)
      readFractionalByteData (strm, bitcount, height, width, image) ;
    else
      readRle8 (strm, height, width, image) ;
    break ;
  case 16:
    {
      BITMAPV4HEADER &header = reinterpret_cast<BITMAPV4HEADER&>(headerbuffer [0]) ;
      unsigned long redmask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4RedMask)) ;
      if (redmask == 0)
        redmask = 0x7C00U ;
      unsigned long greenmask = LittleEndianToSystem (static_cast<UBYTE4>((header.bV4GreenMask))) ;
      if (greenmask == 0)
        greenmask = 0x3E0U ;
      unsigned long bluemask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4BlueMask)) ;
      if (bluemask == 0)
        bluemask = 0x1FU ;
      unsigned long alphamask = 0 ;
      if (headersize >= sizeof (BITMAPV4HEADER))
        alphamask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4AlphaMask)) ;
      read16BitData (strm, height, width, image,
                     redmask, greenmask, bluemask, alphamask) ;
    }
    break ;
  case 24:
    read24BitData (strm, height, width, image) ;
    break ;
  case 32:
    {
      BITMAPV4HEADER &header = reinterpret_cast<BITMAPV4HEADER&>(headerbuffer [0]) ;
      unsigned long redmask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4RedMask)) ;
      if (redmask == 0)
        redmask = 0xFF0000U ;
      unsigned long greenmask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4GreenMask)) ;
      if (greenmask == 0)
        greenmask = 0xFF00U ;
      unsigned long bluemask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4BlueMask)) ;
      if (bluemask == 0)
        bluemask = 0xFFU ;
      unsigned long alphamask = 0 ;
      if (headersize >= sizeof (BITMAPV4HEADER))
        alphamask = LittleEndianToSystem (static_cast<UBYTE4>(header.bV4AlphaMask)) ;
      read32BitData (strm, height, width, image,
                     redmask, greenmask, bluemask, alphamask) ;
    }
    break ;
  }

  callProgressFunction (100) ;
  return ;
}

//
//  Description:
//
//    This function is used to call the progres function.
//
//  Parameters:
//    percent:  The percent complete (0..100)
//
void BmpDecoder::callProgressFunction (unsigned int percent)
{
  if (progress_function == 0)
    return ;
  bool cancel = false ;
  progress_function (*this, progress_data, 1, 1, percent, cancel) ;
  if (cancel)
    throw GraphicsAbort () ;
  return ;
}

void BmpDecoder::readImageFile (const std::string &filename, BitmapImage &image)
{
  ifstream inputstream (filename.c_str (), ios::binary) ;
  if (! inputstream)
    throw BmpError ("Can't open input file") ;
  readImage (inputstream, image) ;
  return ;
}

void BmpDecoder::readFractionalByteData (std::istream &strm,
                                         unsigned int bitcount,
                                         int height, unsigned int width,
                                         BitmapImage &image)
{
  // Number of bits required for each pixel row.
  unsigned int bitwidth = bitcount * width ;
  // Number of bytes need to store each pixel row.
  unsigned int rowwidth = (bitwidth + CHAR_BIT - 1)/CHAR_BIT ;
  // Number of bytes used to store each row in the BMP file.
  // This is is rowwidth rounded up to the nearest 4 bytes.
  unsigned int physicalrowsize = (rowwidth + 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 ; jj < width ; ++ jj, ++ pixel)
      {
         unsigned int color = (buffer [jj/(CHAR_BIT/bitcount)]
                             >> (bitcount * ((CHAR_BIT/bitcount-1) - jj % (CHAR_BIT/bitcount))))
                             & ((1<<bitcount) - 1) ;
         pixel->red = color_table [color].rgbRed ;
         pixel->green = color_table [color].rgbGreen ;
         pixel->blue = color_table [color].rgbBlue ;
      }
    }
  }
  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)
      {
         unsigned int color = (buffer [jj/(CHAR_BIT/bitcount)]
                            >> (bitcount * ((CHAR_BIT/bitcount-1) - jj % (CHAR_BIT/bitcount))))
                            & ((1<<bitcount) - 1) ;
         pixel->red = color_table [color].rgbRed ;
         pixel->green = color_table [color].rgbGreen ;
         pixel->blue = color_table [color].rgbBlue ;
      }
    }
  }
  return ;
}

void BmpDecoder::read8BitData (std::istream &strm,
                               int height, int width,
                               BitmapImage &image)
{
  // This is is rowwidth rounded up to the nearest 4 bytes.
  unsigned int physicalrowsize = (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 ; jj < width ; ++ jj, ++ pixel)
      {
         unsigned int color = buffer [jj] ;
         pixel->red = color_table [color].rgbRed ;
         pixel->green = color_table [color].rgbGreen ;
         pixel->blue = color_table [color].rgbBlue ;
      }
    }
  }
  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)
      {
         unsigned int color = buffer [jj] ;
         pixel->red = color_table [color].rgbRed ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -