SHARE & TOP

我会变成童话里,你爱的那个天使

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

上回我SHARE了一个将PNG转成BMP的方法,通过直接向Buffer里Draw一个PNG来实现的,今天我想共享给大家的是用自己解码来实现PNG转成BMP的方法,这个方法更正统,不过实现也相对比较麻烦一点.

PNG的格式除了几个头以外,关键是它的数据用GZip做了压缩,所以,要实现PNG的解码,需要先了解的背景知识只有两个:1.PNG/BMP的编码格式,2.GZIP的编码格式.这两种文档的编码格式,可以Google一下,会有很多相关资料,我就不再罗嗦了.把自己的实现说一下吧.

1.解开GZIP的方法,我用拿来主义,将网上流传的一个KJava的代码翻译了一下,改写成C代码就OK了.源文件可以点击这里.

在翻译的过程中,注意一下java与c的语法,大体上就可以了,并没有太大难度,好象就是将byte的数组换成byte的指针,记得malloc就一定要free.

2.解析PNG也不复杂,大家可以参考这个文档(中文的,也说的比较清楚).从头里可以得到一些信息(我因为实用的原因,只处理特定的格式,8bit索引).然后,拿到数据,解压缩得以像素值,就可以构造出一个IDIB结构.我们知道IDIB是BREW中唯一能直接操作像素点的接口(如果想手工操作BMP的像素,它是一个很方便的途径).部分代码如下:

boolean PngDecoder_ToBMP(PngDecoder * pMe,byte * pPngRaw,IDIB * pDIB)
{
    
byte * block;
    
byte * data;
    
int i,j,index;
    uint32 len;
    Head head;    


    
if(pPngRaw[0]!=0x89 || pPngRaw[1]!=0x50 || pPngRaw[2]!=0x4E || pPngRaw[3]!=0x47 || pPngRaw[4]!=0x0D || pPngRaw[5]!=0x0A)
        
return FALSE;

    
//缺省认为都是 0x08(8bits color depth) 0x03(调色板)
    IDIB_FlushPalette(pDIB);
    pDIB
->pPaletteMap=NULL;
    pDIB
->nDepth=8;
    pDIB
->nColorScheme=0;
    pDIB
->nPitch=pDIB->cx;
    pDIB
->ncTransparent=IBITMAP_RGBToNative(pMe->pScreen,MAKE_RGB(255,255,255));
    
    
//调色板
    index=33;
    readHead(pPngRaw
+index,&head);
    
if(STRCMP(head.type,"PLTE")==0)
    
{
        len
=head.len;
        index
+=8;        
        pDIB
->pRGB=(uint32*)MALLOC(sizeof(uint32)*(len/3));
        MEMSET(pDIB
->pRGB,0,(len/3)*sizeof(uint32));
        
for(j=0,i=index;i<index+len;j++,i+=3)
        
{
            
//低位
            pDIB->pRGB[j]=((uint32)pPngRaw[i]<<16)+((uint32)pPngRaw[i+1]<<8)+(uint32)pPngRaw[i+2];
            
        }

        pDIB
->cntRGB=j;
        index
+=len+4;
    }

    
    
//读透明色
    readHead(pPngRaw+index,&head);
    
if(STRCMP(head.type,"tRNS")==0)
    
{
        len
=head.len;
        index
+=8;
        j
=(int)pPngRaw[index];
        pDIB
->ncTransparent=IBITMAP_RGBToNative(pMe->pScreen,(RGBVAL)pDIB->pRGB[j]);
        index
+=len+4;        
    }


    
//Step 2: 读数据放入block里
    
//数据长
    readHead(pPngRaw+index,&head);
    
if(STRCMP(head.type,"IDAT")==0)
    
{
        len
=head.len;  
        block
=(byte*)MALLOC(len);
        
        index
+=10//IDAT块前面两个字节是标志:0x78 0x5E
        
        MEMSET(block,
0,len);
        MEMCPY(block,
&pPngRaw[index],len);
        
        
//Step 3:解压缩
        
        data 
= GZIP_Inflate(pMe->gzip,block,pDIB->cx*pDIB->cy+pDIB->cy);
        len
=pMe->gzip->uncompressed_index;

        pDIB
->pBmp=(byte*)MALLOC(pDIB->cx*pDIB->cy);
        
for(i=0;i<pDIB->cy;i++)
            
for(j=0;j<pDIB->cx;j++)
            
{
                pDIB
->pBmp[i*pDIB->cx+j]=data[i*(pDIB->cx+1)+j+1];
            }

        

        FREEIF(block);
        block
=NULL;
        FREEIF(data);    
        data
=NULL;
    }

    
    
return TRUE;
}

pPngRaw是加载的PNG图像数据,可以来自于文件或网络,转换的结果放到pDIB里.

 

posted on 2006-05-09 11:08  Android@SHARETOP  阅读(3672)  评论(7编辑  收藏  举报