一、运行环境介绍
Linux系统: Redhat6.3 (32位)
gcc 版本 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
二、功能介绍
打开一张BMP图片,读取RGB源数据进行缩放再生成新的BMP图片。
三、核心代码
由于处理的是BMP图片数据,传入的缩放后的图片宽度需要是4的倍数.
缩放算法参考: http://blog.chinaunix.net/uid-22915173-id-2185545.html
#include <stdio.h> #include <string.h> #include <stdlib.h> int PicZoom(unsigned char *s_buff,unsigned int s_width,unsigned int s_height,unsigned char *buff,unsigned int width,unsigned int height); void *my_memcpy(void *v_dst,const void *v_src,unsigned char c); #pragma pack(1) /* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */ /*需要文件信息头:14个字节 */ struct BITMAPFILEHEADER { unsigned short bfType; //保存图片类似。 'BM' unsigned long bfSize; //图片的大小 unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; //RGB数据偏移地址 }; /* 位图信息头 */ struct BITMAPINFOHEADER { /* bmih */ unsigned long biSize; //结构体大小 unsigned long biWidth; //宽度 unsigned long biHeight; //高度 unsigned short biPlanes; unsigned short biBitCount; //颜色位数 unsigned long biCompression; unsigned long biSizeImage; unsigned long biXPelsPerMeter; unsigned long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; }; /* 图片放大与缩小示例 */ int main(int argc,char *argv[]) { struct BITMAPFILEHEADER src_head; //源文件头数据 struct BITMAPINFOHEADER src_info; //源文件参数结构 struct BITMAPFILEHEADER new_head; //新文件头数据 struct BITMAPINFOHEADER new_info; //新文件参数结构 unsigned int new_Width; //缩放后的宽度 unsigned int new_Height; //缩放后的高度 unsigned char *new_buff; //存放新图片的数据 unsigned char *src_buff; //存放源图片的数据 unsigned int cnt=0; if(argc!=5) { printf("参数格式: ./a.out <原图片名称> <新图片名称> <缩放后宽度> <缩放后高度>\n"); printf("例如: ./a.out src.bmp new.bmp 80 80 \n"); return 0; } /*1. 打开图片文件*/ FILE *src_file=fopen(argv[1],"rb"); FILE *new_file=fopen(argv[2],"wb"); if(src_file==NULL||new_file==NULL) { printf("%s 源文件打开失败!\r\n",argv[1]); return; } /*2. 读取源图片参数*/ fread(&src_head,sizeof(struct BITMAPFILEHEADER),1,src_file); fread(&src_info,sizeof(struct BITMAPINFOHEADER),1,src_file); printf("源图片尺寸:w=%d h=%d\r\n",src_info.biWidth,src_info.biHeight); /*3. 获取新图片的尺寸*/ new_Width=atoi(argv[3]); new_Height=atoi(argv[4]); printf("新图片尺寸:w=%d h=%d\r\n",new_Width,new_Height); /*4. 申请存放图片数据的空间*/ src_buff=malloc(src_info.biWidth*src_info.biHeight*3); new_buff=malloc(new_Width*new_Height*3); if(new_buff==NULL||src_buff==NULL) { printf("malloc申请空间失败!\r\n"); return -1; } /*5. 读取源图片RGB数据*/ fseek(src_file,src_head.bfOffBits,SEEK_SET); //移动文件指针到RGB数据位置 fread(src_buff,1,src_info.biWidth*src_info.biHeight*3,src_file); //读取源数据 /*6. 缩放图片*/ if(PicZoom(src_buff,src_info.biWidth,src_info.biHeight,new_buff,new_Width,new_Height)) { printf("图片缩放处理失败!\r\n"); return -1; } /*7. 写入新图片数据*/ //填充文件头 memset(&new_head,0,sizeof(struct BITMAPFILEHEADER)); new_head.bfType=0x4d42; new_head.bfSize=54+new_Width*new_Height*3; new_head.bfOffBits=54; //填充文件参数 memset(&new_info,0,sizeof(struct BITMAPINFOHEADER)); new_info.biSize=sizeof(struct BITMAPINFOHEADER); new_info.biWidth=new_Width; new_info.biHeight=new_Height; new_info.biPlanes=1; new_info.biBitCount=24; //写入文件数据 fwrite(&new_head,sizeof(struct BITMAPFILEHEADER),1,new_file); fwrite(&new_info,sizeof(struct BITMAPINFOHEADER),1,new_file); fseek(new_file,new_head.bfOffBits,SEEK_SET); //移动文件指针到RGB数据位置 cnt=fwrite(new_buff,1,new_info.biWidth*new_info.biHeight*3,new_file); //写数据 /*8. 关闭图片文件*/ fclose(new_file); fclose(src_file); printf("%s 新图片创建成功! 路径:程序运行路径下\r\n",argv[2]); return 0; } /********************************************************************** * 函数名称: PicZoom * 功能描述: 近邻取样插值方法缩放图片 * 注意该函数会分配内存来存放缩放后的图片,用完后要用free函数释放掉 * "近邻取样插值"的原理请参考网友"lantianyu520"所著的"图像缩放算法" * 输入参数: ptOriginPic - 内含原始图片的象素数据 * ptZoomPic - 内含缩放后的图片的象素数据 * 输出参数: 无 * 返 回 值: 0 - 成功, 其他值 - 失败 ***********************************************************************/ int PicZoom(unsigned char *ptOriginPic_aucPixelDatas,unsigned int ptOriginPic_iWidth,unsigned int ptOriginPic_iHeight,unsigned char *ptZoomPic_aucPixelDatas,unsigned int ptZoomPic_iWidth,unsigned int ptZoomPic_iHeight) { unsigned int ptOriginPic_iLineBytes=ptOriginPic_iWidth*3; //一行的字节数 unsigned int ptZoomPic_iLineBytes=ptZoomPic_iWidth*3; //一行的字节数 unsigned long dwDstWidth=ptZoomPic_iWidth; unsigned long* pdwSrcXTable; unsigned long x; unsigned long y; unsigned long dwSrcY; unsigned char *pucDest; unsigned char *pucSrc; unsigned long dwPixelBytes=3; //像素字节 pdwSrcXTable=malloc(sizeof(unsigned long) * dwDstWidth); if(NULL==pdwSrcXTable) { return -1; } for(x=0; x < dwDstWidth; x++)//生成表 pdwSrcXTable { pdwSrcXTable[x]=(x*ptOriginPic_iWidth/ptZoomPic_iWidth); } for(y=0; y < ptZoomPic_iHeight; y++) { dwSrcY=(y * ptOriginPic_iHeight/ptZoomPic_iHeight); pucDest=ptZoomPic_aucPixelDatas + y * ptZoomPic_iLineBytes; pucSrc=ptOriginPic_aucPixelDatas+dwSrcY * ptOriginPic_iLineBytes; for(x=0; x <dwDstWidth; x++) { my_memcpy(pucDest+x*dwPixelBytes,pucSrc+pdwSrcXTable[x]*dwPixelBytes,dwPixelBytes); } } free(pdwSrcXTable); return 0; } /* 函数功能:内存拷贝函数 */ void *my_memcpy(void *v_dst,const void *v_src,unsigned char c) { const char *src=v_src; char *dst=v_dst; while(c--)*dst++=*src++; return v_dst; }
四、运行示例
[wbyq@wbyq linux_c]$ gcc app.c [wbyq@wbyq linux_c]$ ./a.out 参数格式: ./a.out <原图片名称> <新图片名称> <缩放后宽度> <缩放后高度> 例如: ./a.out src.bmp new.bmp 80 80 [wbyq@wbyq linux_c]$ ./a.out 666.bmp 1.bmp 80 80 源图片尺寸:w=800 h=383 新图片尺寸:w=80 h=80 1.bmp 新图片创建成功! 路径:程序运行路径下 [wbyq@wbyq linux_c]$ eog 1.bmp