图象处理

  今天研究了一下位图的加载,以BMP为例,本来在WIN32下,可以直接LoadImage,然而这个函数太通用了,以至于对于图像的很多东西都不很清楚,具体对图像操作是很麻烦。
  对于一个设备无关的位图(DIB),主要由4部分组成
  1文件头
  2信息头
  3RGB色彩表(不一定有)
  4位图像素位
  对于文件头,其定义如下,参照MSDN
typedef struct tagBITMAPFILEHEADER { // bmfh
    WORD    bfType;         //signature word “BM” or 0X4D42
    DWORD   bfSize;         //entire size of file
    WORD    bfReserved1;    //must be zero
    WORD    bfReserved2;    //must be zero
    DWORD   bfOffBits;      //offset in file of DIB pixel bits
} BITMAPFILEHEADER;


对于Windows DIB,紧跟在文件头后的信息头定义如下
typedef struct tagBITMAPINFOHEADER{ // bmih
    DWORD  biSize;
    LONG   biWidth;          //size of the structure
    LONG   biHeight;         //width of the image in pixels
    WORD   biPlanes;         //height of the image in pixels
    WORD   biBitCount        // = 1
    DWORD  biCompression;    //bits per pixel
    DWORD  biSizeImage;      //compression code
    LONG   biXPelsPerMeter;  //number of bytes in image
    LONG   biYPelsPerMeter;  //horizontal resolution
    DWORD  biClrUsed;        //number of colors used
    DWORD  biClrImportant;   //number of important colors
} BITMAPINFOHEADER;

对于色彩表,其定义如下
typedef struct tagRGBQUAD { // rgbq
    BYTE    rgbBlue;         //blue level
    BYTE    rgbGreen;        //green level
    BYTE    rgbRed;          //red level
    BYTE    rgbReserved;     // = 0
} RGBQUAD;

而对于像素位,是由从图像的底行开始,并沿着图像向上增长的水平行组织的

  了解了DIB的基本结构后,对DIB的操作就可以自己写出来了,我写了一个
CPicture类,进行对DIB的操作,首先是产生DIB
BOOL CPicture::Create(int _width, int _height, int _depth)
{
    width = _width;
 height = _height;
 depth = _depth;

 bytes_per_line = ScanBytes(width, depth);
 bytes_per_pixel = PixelBytes(depth);

 long bitsAlloc = bytes_per_line * height;
 long headersize = sizeof(BITMAPINFOHEADER);

 if(depth == 8)
  headersize += sizeof(RGBQUAD) * 256;

 if((hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, bitsAlloc + headersize)) == 0)
  return FALSE;

 Info = (BITMAPINFO *)::GlobalLock(hGlobal);
 Bits = (void*)((long*)Info + headersize);

 Info->bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
 Info->bmiHeader.biWidth         = width;
    Info->bmiHeader.biHeight        = height;
 Info->bmiHeader.biBitCount      = (unsigned short)depth;
 Info->bmiHeader.biPlanes        = 1;
 Info->bmiHeader.biXPelsPerMeter = 0;
 Info->bmiHeader.biYPelsPerMeter = 0;
 Info->bmiHeader.biClrUsed       = 0;
 Info->bmiHeader.biClrImportant  = 0;
 Info->bmiHeader.biCompression   = BI_RGB;
 Info->bmiHeader.biSizeImage     = bitsAlloc;

 return TRUE;
}

然后就是读入BMP文件
BOOL CPicture::LoadPicture(CFile &file, int ox, int oy)
{
 BITMAPFILEHEADER header;
 BITMAPINFOHEADER infoheader;

 if(file.Read(&header, sizeof(header)) != sizeof(header)
  || header.bfType != (WORD)(('M' << 8) | 'B')
  || file.Read(&infoheader, sizeof(infoheader)) != sizeof(infoheader)
  || infoheader.biSize < sizeof(BITMAPINFOHEADER)
  || infoheader.biCompression != BI_RGB)
  return FALSE;

 int _width  = infoheader.biWidth;
 int _height = infoheader.biHeight;
 int _depth  = infoheader.biBitCount;

 if(!Create(_width + ox, _height + oy, _depth))
  return FALSE;

 if(_width + ox > Width() || _height + oy > Height() || _depth != Depth())
  return FALSE;

 int bits_off = sizeof(BITMAPFILEHEADER) + infoheader.biSize;
 
 if(_depth == 8)
 {
  int csize = sizeof(RGBQUAD) * 256;
  if(file.Read(Info->bmiColors, csize) != csize)
   return FALSE;
  bits_off += csize;
 }

 file.Seek(bits_off, CFile::begin);

 int length = _width * BytesPerPixel();
 int filler = ScanBytes(_width, _depth) - length;
 
 
 for(int y = _height - 1; y >= 0; y--)
 {  
  if(file.Read(GetBits(ox, oy + y), length) != length)
   return FALSE;

  if(filler)
   file.Seek(filler, CFile::current);
 }

// file.Read(GetBits(), infoheader.biSizeImage);
 return TRUE;
}

另外还写了图像的复制与重叠函数:
//图像复制
void CPicture::Copy(const CPicture *picture, RECT &rect)
{
 int len = (rect.right - rect.left) * 3;
 for(int y = rect.top; y < rect.bottom; y++)
 {
  memcpy(GetBits(rect.left, y), picture->GetBits(rect.left, y), len);
 }
}

//图像重叠
void CPicture::MixPicture(const CPicture *picture, RECT &rect, COLORREF trans_color)
{
 const unsigned char trans_b = GetBValue(trans_color);
 const unsigned char trans_g = GetGValue(trans_color);
 const unsigned char trans_r = GetRValue(trans_color);

 for(int y = rect.top; y < rect.bottom; y++)
 {
  char *p = (char *)GetBits(rect.left, y);
  const BYTE * q = (BYTE *)picture->GetBits(rect.left, y);
  for(int x = rect.left; x < rect.right; x++)
  {
   const BYTE b = *q++;
   const BYTE g = *q++;
   const BYTE r = *q++;

   if(b != trans_b || g != trans_g || r != trans_r)
   {
    p[0] = b;
    p[1] = g;
    p[2] = r;
   }
   p += 3;
  }
 }
}

然后又写了一个CPictureDraw类,专门用来加载并显示24位的位图
//创建显示用图像,选用24位位图
BOOL CPictureDraw::Create(HDC dc, int _width, int _height)
{
 width = _width;
 height = _height;
 depth = 24;

 bytes_per_line = ScanBytes(_width, 24);
 bytes_per_pixel = PixelBytes(24);

 InfoHeader.biSize          = sizeof(BITMAPINFOHEADER);
 InfoHeader.biWidth         = _width;
 InfoHeader.biHeight        = _height;
 InfoHeader.biBitCount      = 24;
 InfoHeader.biPlanes        = 1;
 InfoHeader.biXPelsPerMeter = 0;
 InfoHeader.biYPelsPerMeter = 0;
 InfoHeader.biClrUsed       = 0;
 InfoHeader.biClrImportant  = 0;
 InfoHeader.biCompression   = BI_RGB;
 InfoHeader.biSizeImage     = bytes_per_line * _height;

 Info =(BITMAPINFO*)&InfoHeader;
 hBitmap = CreateDIBSection(dc, Info, DIB_RGB_COLORS, &Bits, NULL, 0);

 return hBitmap != 0;
}

在调用Draw函数就可实现图像的显示
//绘制图形 
void CPictureDraw::Draw(HDC dc, int x, int y, int w, int h, int ox, int oy)
{
 HDC  memdc = CreateCompatibleDC(dc);
 HGDIOBJ oldbmp = SelectObject(memdc, hBitmap);
 BitBlt(dc, x, y, w, h, memdc, ox, oy, SRCCOPY);
 GdiFlush();
 SelectObject(memdc, oldbmp);
 DeleteDC(memdc);
}

void CPictureDraw::Draw(HDC dc, RECT &rect, POINT &point)
{
 Draw(dc, rect.left, rect.top, rect.right - rect.left,
   rect.bottom - rect.top, point.x, point.y);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值