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

📄 openbmp.cpp

📁 这个刚才那个的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// format information gleaned from
//   http://www.daubnet.com/formats/BMP.html
// and
//   http://www.edm2.com/0107/os2bmp.html
//
// If you have Visual Studio.NET:
//   ms-help://MS.VSCC/MS.MSDNVS/gdi/bitmaps_7c36.htm

#include <string.h>
#include "corona.h"
#include "SimpleImage.h"
#include "Utility.h"


namespace corona {

  struct Header {
    bool os2;

    int file_size;
    int data_offset;
    int width;
    int height;
    int bpp;
    int compression;

    int pitch;  // number of bytes in each scanline
    int image_size;

    auto_array<BGR> palette;
    int palette_size;

    // for bitfield specification...
    //                               /*- 16-bit only -*/
    u32 bf_red_mask,   bf_red_shift,   bf_red_rshift;
    u32 bf_green_mask, bf_green_shift, bf_green_rshift;
    u32 bf_blue_mask,  bf_blue_shift,  bf_blue_rshift;
  };


  bool   ReadHeader(File* file, Header& h);
  bool   ReadInfoHeader(File* file, Header& h);
  bool   ReadPalette(File* file, Header& h);
  Image* DecodeBitmap(File* file, const Header& h);

  
  Image* OpenBMP(File* file) {
    Header h;
    if (ReadHeader(file, h) &&
        ReadInfoHeader(file, h) &&
        ReadPalette(file, h)) {

      return DecodeBitmap(file, h);

    } else {

      return 0;

    }
  }


  bool ReadHeader(File* file, Header& h) {
    byte header[14];
    if (file->read(header, 14) != 14) {
      return false;
    }

    // check signature
    if (header[0] != 'B' || header[1] != 'M') {
      return false;
    }

    h.file_size   = read32_le(header + 2);
    h.data_offset = read32_le(header + 10);
    return true;
  }


  bool ReadInfoHeader(File* file, Header& h) {

    const int HEADER_READ_SIZE = 24;

    // read the only part of the header we need
    byte header[HEADER_READ_SIZE];
    if (file->read(header, HEADER_READ_SIZE) != HEADER_READ_SIZE) {
      return false;
    }

    int size = read32_le(header + 0);
    int width;
    int height;
    int planes;
    int bpp;
    int compression;
    int image_size;

    if (size < 40) {  // assume OS/2 bitmap
      if (size < 12) {
        return false;
      }

      h.os2 = true;
      width  = read16_le(header + 4);
      height = read16_le(header + 6);
      planes = read16_le(header + 8);
      bpp    = read16_le(header + 10);
      compression = 0;
      image_size = 0;
      
    } else {

      h.os2 = false;
      width       = read32_le(header + 4);
      height      = read32_le(header + 8);
      planes      = read16_le(header + 12);
      bpp         = read16_le(header + 14);
      compression = read32_le(header + 16);
      image_size  = read32_le(header + 20);

    }
    
    // sanity check the info header
    if (planes != 1) {
      return false;
    }

    // adjust image_size
    // (if compression == 0 or 3, manually calculate image size)
    int line_size = 0;
    if (compression == 0 || compression == 3) {
      line_size = (width * bpp + 7) / 8;
      line_size = (line_size + 3) / 4 * 4;  // 32-bit-aligned
      image_size = line_size * height;
    }

    h.width       = width;
    h.height      = height;
    h.bpp         = bpp;
    h.compression = compression;
    h.pitch       = line_size;
    h.image_size  = image_size;

    // jump forward (backward in the OS/2 case :) to the palette data
    file->seek(size - HEADER_READ_SIZE, File::CURRENT);

    return true;
  }

  // count the number of consecutive zeroes on the right side of a
  // binary number
  // 0x00F0 will return 4
  int count_right_zeroes(u32 n) {
    int total = 0;
    u32 c = 1;
    while ((total < 32) && ((n & c) == 0)) {
      c <<= 1;
      ++total;
    }
    return total;
  }

  // count the number of ones in a binary number
  // 0x00F1 will return 5
  int count_ones(u32 n) {
    int total = 0;
    u32 c = 1;
    for (int i = 0; i < 32; ++i) {
      if (n & c) {
        ++total;
      }
      c <<= 1;
    }
    return total;
  }

  bool ReadPalette(File* file, Header& h) {

    // initialize bit masks/shifts...  just in case
    h.bf_red_mask   = h.bf_red_shift   = h.bf_red_rshift   = 0;
    h.bf_green_mask = h.bf_green_shift = h.bf_green_rshift = 0;
    h.bf_blue_mask  = h.bf_blue_shift  = h.bf_blue_rshift  = 0;

    // if we're not a palettized image, don't even read a palette
    if (h.bpp > 8) {
      h.palette_size = 0;

      // do we have bitfields?
      if (h.compression == 3) {

        auto_array<byte> bitfields(new byte[12]);
        if (file->read(bitfields, 12) != 12) {
          return false;
        }

        h.bf_red_mask   = read32_le((byte*)bitfields);
        h.bf_green_mask = read32_le((byte*)bitfields + 4);
        h.bf_blue_mask  = read32_le((byte*)bitfields + 8);

        // calculate shifts
        h.bf_red_shift    = count_right_zeroes(h.bf_red_mask);
        h.bf_green_shift  = count_right_zeroes(h.bf_green_mask);
        h.bf_blue_shift   = count_right_zeroes(h.bf_blue_mask);
        h.bf_red_rshift   = 8 - count_ones(h.bf_red_mask);
        h.bf_green_rshift = 8 - count_ones(h.bf_green_mask);
        h.bf_blue_rshift  = 8 - count_ones(h.bf_blue_mask);

      // otherwise, set default bitfield entries
      } else {

        if (h.bpp == 16) {

          h.bf_red_mask     = 0x7C00;
          h.bf_red_shift    = 10;
          h.bf_red_rshift   = 3;

          h.bf_green_mask   = 0x03E0;
          h.bf_green_shift  = 5;
          h.bf_green_rshift = 3;

          h.bf_blue_mask    = 0x001F;
          h.bf_blue_shift   = 0;
          h.bf_blue_rshift  = 3;

        } else if (h.bpp == 32) {

          // these don't need any rshift
          h.bf_red_mask   = 0x00FF0000; h.bf_red_shift   = 16;
          h.bf_green_mask = 0x0000FF00; h.bf_green_shift = 8;
          h.bf_blue_mask  = 0x000000FF; h.bf_blue_shift  = 0;

        }
      }

      return true;
    }

    if (h.bpp <= 8) {
      h.palette_size = 1 << h.bpp;
    } else {
      h.palette_size = 0;
      return true;
    }
    h.palette = new BGR[h.palette_size];

    // read the BMP color table
    const int buffer_size = h.palette_size * (h.os2 ? 3 : 4);
    auto_array<byte> buffer(new byte[buffer_size]);
    if (file->read(buffer, buffer_size) != buffer_size) {
      return false;
    }

    byte* in = buffer;
    BGR* out = h.palette;
    for (int i = 0; i < h.palette_size; ++i) {
      out->blue  = *in++;
      out->green = *in++;
      out->red   = *in++;
      if (!h.os2) {
        ++in;  // skip alpha
      }
      ++out;
    }

    return true;
  }


  bool advance(int& x, int& y, const Header& h) {
    if (++x >= h.width) {
      x = 0;
      if (++y >= h.height) {
        return false;
      }
    }
    return true;
  }

  Image* ReadBitmap1(const byte* raster_data, const Header& h) {
    auto_array<byte> pixels(new byte[h.width * h.height]);
    
    auto_array<BGR> palette(new BGR[256]);
    memset(palette, 0, 256 * sizeof(BGR));
    memcpy(palette, h.palette, h.palette_size * sizeof(BGR));

    for (int i = 0; i < h.height; ++i) {
      const byte* in = raster_data + i * h.pitch;
      byte* out = pixels + (h.height - i - 1) * h.width;

      int mask = 128;
      for (int j = 0; j < h.width; ++j) {
        *out++ = (*in & mask) > 0;

        mask >>= 1;
        if (mask == 0) {
          ++in;
          mask = 128;
        }
      }
    }

    return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
                           (byte*)palette.release(), 256, PF_B8G8R8);
  }

  Image* ReadBitmap4(const byte* raster_data, const Header& h) {
    auto_array<byte> pixels(new byte[h.width * h.height]);
    
    auto_array<BGR> palette(new BGR[256]);
    memset(palette, 0, 256 * sizeof(BGR));
    memcpy(palette, h.palette, h.palette_size * sizeof(BGR));

    for (int i = 0; i < h.height; ++i) {
      const byte* in = raster_data + i * h.pitch;
      byte* out = pixels + (h.height - i - 1) * h.width;

      for (int j = 0; j < h.width / 2; ++j) {
        *out++ = (*in >> 4);
        *out++ = (*in & 0x0F);

        ++in;
      }

      if (h.width % 2) {
        *out++ = (*in >> 4);
      }
    }

    return new SimpleImage(h.width, h.height, PF_I8, pixels.release(),
                           (byte*)palette.release(), 256, PF_B8G8R8);
  }

  Image* ReadBitmapRLE4(const byte* raster_data, const Header& h) {
    auto_array<byte> pixels(new byte[h.width * h.height]);
    
    auto_array<BGR> palette(new BGR[256]);
    memset(palette, 0, 256 * sizeof(BGR));
    memcpy(palette, h.palette, h.palette_size * sizeof(BGR));

    // by default, we have an empty bitmap

⌨️ 快捷键说明

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