PPM格式转化为BMP格式的实现

在网上找了好久都没能找到PPM格式的详细的编码规则, http://wangbingkun.spaces.live.com/blog/cns!E188E2874053C244!215.entry 链接给出了简单的介绍。于是我就利用Matlab读取出一幅PPM格式的图片,然后再用WinEdit读取该图片的内存分布,通过对比发现其主要由以下几个部分组成:

1、文件类型,我所选取的PPM格式是P6,占据前两个字节(第0,1字节),16进制表示为 50 36;

2、图片的像素宽度,与文件类型隔一个字节,如宽度512存储时占据三个字节(第3,4,5字节),16进制表示为35 31 32;

3、图片的像素高度,与宽度也是隔一个字节,表示方式和宽度相同,如果宽度为一个三位数,则高度值从第7字节开始存放,如果宽度为一个二位数,则高度从第6字节开始存放;

4、图片的最大像素值,与高度也是隔一个字节,当然其具体的存放位置和宽度和高度的位数有关系的。

5、图像数据区,与最大像素值隔一个字节,P6类型的是每个像素三个字节,整个图像的扫描顺序是从左到右,由上而下,每个像素内部的三个字节按照BGR顺序排列的。

根据以上的分析,下面给出一段将P6类型的PPM格式转化为BMP格式的代码:

HDIB CDibImage::ReadPPMFile(CFile& file)
{
 unsigned char * pHeader=new unsigned char [15];
 HDIB hDIB_Des;                         
 LPSTR pDIB_Des;

 HDIB hPPM_Src;
 LPSTR pPPM_Src;

 DWORD dwSrc=file.GetLength();  // 获取源文件的长度

 file.Read(pHeader, 15);
 if(pHeader[0]!=80||pHeader[1]!=54)  //判断是否是P6格式
 {
  AfxMessageBox("不是P6格式!");
  return NULL;
 }

 int j=0, flag[4];                 // 找出主要参数的分隔符的位置
 for (int i=2; i<15; i++)
 {
  if(pHeader[i]>57||pHeader[i]<48)
  {
   flag[j]=i;
   j++;
   if(j>3)
    break;
  }
 }

 if(flag[0]!=2)
  return NULL;

 int lenWidth=0, lenHeight=0, maxColorNum=0;     //分别得出原始图像的宽度和高度
 for (i=1; i<flag[1]-flag[0]; i++)
 {
  lenWidth=lenWidth*10+pHeader[flag[0]+i]%16;
 }
 for (i=1; i<flag[2]-flag[1]; i++)
 {
  lenHeight=lenHeight*10+pHeader[flag[1]+i]%16;
 }
 for (i=1; i<flag[3]-flag[2]; i++)
 {
  maxColorNum=maxColorNum*10+pHeader[flag[2]+i]%16;
 }

   
 int rowLenDes=WIDTHBYTES(24*lenWidth);    //分别给出位图的宽度和高度
 int heightLenDes=lenHeight;
 int dwData=rowLenDes*heightLenDes;      //位图数据区大小
    int dwInfo=40;
 int dwTotal=dwInfo+dwData;             
//这里构造的是24位位图


 hPPM_Src = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSrc);
 if (hPPM_Src == 0)
 {
  return NULL;
 }
 pPPM_Src = (LPSTR) ::GlobalLock((HGLOBAL) hPPM_Src);
 DWORD aaa=file.ReadHuge(pPPM_Src, dwSrc-flag[3]-1);
 if (aaa!=dwSrc-flag[3]-1)  // 读象素
 {
  ::GlobalUnlock((HGLOBAL) hPPM_Src);
  ::GlobalFree((HGLOBAL) hPPM_Src);
  return NULL;
 }


 hDIB_Des = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwTotal);
 if (hDIB_Des == 0)
 {
  return NULL;
 }
 pDIB_Des=(LPSTR)GlobalLock((HGLOBAL)hDIB_Des);

 BYTE *pDIBBits=(BYTE*)(40+pDIB_Des);
 int lenRow=3*lenWidth;
 for(i=0; i<lenHeight; i++)
 {
  for(j=0; j<lenRow; j=j+3)
  {
   pDIBBits[i*rowLenDes+j]=pPPM_Src[(lenHeight-i)*lenRow+j+2];     //此处考虑到了PPM的BGR的排列顺序
   pDIBBits[i*rowLenDes+j+1]=pPPM_Src[(lenHeight-i)*lenRow+j+1];
   pDIBBits[i*rowLenDes+j+2]=pPPM_Src[(lenHeight-i)*lenRow+j];

  }  
  if(rowLenDes>lenRow)
  {
   for(j=lenRow; j<rowLenDes; j++)
   {
    pDIBBits[i*rowLenDes+j]=0;
   }
  }
 
 }

 ((LPBITMAPINFOHEADER)pDIB_Des)->biHeight=heightLenDes;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biWidth=lenWidth;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biClrUsed=0;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biSize=40;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biBitCount=24;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biPlanes=1;
 ((LPBITMAPINFOHEADER)pDIB_Des)->biSizeImage=heightLenDes*lenWidth;

 ::GlobalUnlock((HGLOBAL) hDIB_Des);
 ::GlobalUnlock((HGLOBAL) hPPM_Src);
 ::GlobalFree((HGLOBAL) hPPM_Src);
 return hDIB_Des;
}

于我在实现这一转换的时候不知道PPM的具体的数据格式,仅是凭自己机器中存放的PPM格式的图像得出的规律而实现的,望知道PPM更详细信息的朋友多多指点。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值