一、运行环境介绍
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
代码语言:javascript复制#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 源文件打开失败!rn",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=%drn",src_info.biWidth,src_info.biHeight);
/*3. 获取新图片的尺寸*/
new_Width=atoi(argv[3]);
new_Height=atoi(argv[4]);
printf("新图片尺寸:w=%d h=%drn",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申请空间失败!rn");
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("图片缩放处理失败!rn");
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 新图片创建成功! 路径:程序运行路径下rn",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;
}
四、运行示例
代码语言:javascript复制[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