C语言实现的BMP和JPEG图片的解码

/*
这是read_picture.c 文件的代码 ,主要是对输入的图片的文件(BMP和JPEG类型)进行解码,转换成在LCD中显示的数据;
使用该程序时,要先把jpeglib库文件和头文件放到对应的标谁库和标准头文件中;否则编译出错的
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include


#include "jpeglib.h"
#include
#include
#include
#include


unsigned char* read_bmp(char* filename);
unsigned char* read_jpeg(char *path);


//14byte文件头
typedef struct
{
char cfType[2];//文件类型,"BM"(0x4D42)
long cfSize;//文件大小(字节)
long cfReserved;//保留,值为0
long cfoffBits;//数据区相对于文件头的偏移量(字节)
}__attribute__((packed)) BITMAPFILEHEADER;
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐


//40byte信息头
typedef struct
{
char ciSize[4];//BITMAPFILEHEADER所占的字节数
long ciWidth;//宽度
long ciHeight;//高度
char ciPlanes[2];//目标设备的位平面数,值为1
int ciBitCount;//每个像素的位数
char ciCompress[4];//压缩说明
char ciSizeImage[4];//用字节表示的图像大小,该数据必须是4的倍数
char ciXPelsPerMeter[4];//目标设备的水平像素数/米
char ciYPelsPerMeter[4];//目标设备的垂直像素数/米
char ciClrUsed[4]; //位图使用调色板的颜色数
char ciClrImportant[4]; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
}__attribute__((packed)) BITMAPINFOHEADER;


typedef struct
{
unsigned char blue;
unsigned char green;
unsigned char red;
//unsigned char reserved;
}__attribute__((packed)) PIXEL;//颜色模式RGB


BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;


int width_bmp;
int height_bmp;


/*
第1 个参数: 图片所在的路径名
第2 个参数: 没有任何作用,先将他设置为空
返回值: 返回一个指向堆的指针,是解码后的图片数据
*/
int read_picture_type(char *pic_name)//根据文析名得到图片的类型
{
char *pic_tail;
int name_len = strlen(pic_name);
pic_tail = pic_name + name_len-1;
while(pic_name != pic_tail)
{
if(*pic_tail == '.')
{

if(strcmp(pic_tail,".bmp") == 0 || strcmp(pic_tail,".BMP") == 0)
{
return 2;
}
if(strcmp(pic_tail,".jpg") == 0 || strcmp(pic_tail,".JPG") == 0)
{
return 1;
}

}
pic_tail--;
}
printf("This is not bmp or jpg file\n");
return 0;
}


/*
参数1 pic_name: 是要解码图片的路径
返回值:是返回一个指向解码后数据指针
*/
unsigned char *read_picture(char *pic_name)//根据图片的类型,调用对应的解码函数进行解码,返回一个指向解码后数据的指针
{
int pic_type = read_picture_type(pic_name);


switch(pic_type)//根据图片类型不同,调用不同函数来解码
{
case 0: 
printf("picture file ERR\n\n");
return NULL;
break;

case 1: //如果是JPEG图片
return read_jpeg(pic_name);
break;

case 2://如果是BMP图片
return read_bmp(pic_name);
break;
}

return NULL;
}


/*
参数1:是BMP图片的路径
返回一个指向堆分配空间指针,存放图片解码后的数据
*/
unsigned char* read_bmp(char* filename)//BMP类型图片的解码,
{
FILE *fp;
int rc;
int line_x, line_y;
long int location = 0, BytesPerLine1 = 0,BytesPerLine2 = 0;
unsigned char* image;


fp = fopen(filename, "rb" );
if (fp == NULL)
{
printf("openerr\n");
return( NULL);
}


rc = fread( &FileHead, sizeof(BITMAPFILEHEADER), 1, fp );//读取文件头
if ( rc != 1)
{
printf("read header error!\n");
fclose( fp );
return( NULL );
}


//检测是否是bmp图像
if (memcmp( FileHead.cfType, "BM", 2) != 0)
{
printf("it's not a BMP file\n");
fclose( fp );
return( NULL );
}


rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );//读取信息头
if ( rc != 1)
{
printf("read infoheader error!\n");
fclose( fp );
return( NULL );
}


//跳转的数据区  FileHead.cfoffBits是始止位距数据区的偏移量
fseek(fp, FileHead.cfoffBits, SEEK_SET);
//每行字节数   InfoHead,是BMP文件的信息头  ciBitCount对应图片的位深度


BytesPerLine1 = ((InfoHead.ciWidth * 16) / 32) * 4;//生成后的,16的偏移量,
BytesPerLine2 = (InfoHead.ciWidth * InfoHead.ciBitCount+31 ) / 32 * 4;//图片本身一行数据的偏移量 


//printf("BytesPerLine==%d\n",BytesPerLine);
//printf("ciWidth==%d\n",InfoHead.ciWidth);
//printf("ciHeight==%d\n",InfoHead.ciHeight);
width_bmp=InfoHead.ciWidth;
height_bmp=InfoHead.ciHeight;
image=(unsigned char*)malloc(width_bmp*height_bmp*2);
if(InfoHead.ciWidth%2 != 0)
width_bmp=InfoHead.ciWidth-1;


line_x = line_y = 0;
unsigned short short_buf;
PIXEL pix;


while(!feof(fp))
{

rc = fread( (char *)&pix, 1, sizeof(PIXEL), fp);//读一个像素点,放到pix这个结构体中
if (rc != sizeof(PIXEL))
break;
location = line_x *16 / 8 + (InfoHead.ciHeight - line_y -1) * BytesPerLine1;
//显示每一个像素
short_buf=(((pix.red&0xf8)>>3)<<11)|(((pix.green&0xfc) >> 2) << 5) | ((pix.blue&0xf8) >> 3);
//上面一个像素点已经变成16位的了,所以分成两个8位的,写入到数组中
*(image + location + 0) = (char)(short_buf&0xff);
*(image + location + 1) = (char)((short_buf&0xff00) >> 8);

line_x++;//当前是那个像素点,bits_per_pixel/8是每个像素占多少位字节
if (line_x == InfoHead.ciWidth )
{
line_x = 0;//对应一行中的那个像素
line_y++;//对应那一行
fseek(fp, BytesPerLine2*line_y+FileHead.cfoffBits, SEEK_SET);//重定位,偏移量指针
if(line_y == InfoHead.ciHeight)
break;
}
}
fclose( fp );
return (image);
}


/*
这是jpeg图片的解码
参数1:是jpeg图片的路径
返回 :返回一个解码后的数据
*/
unsigned char* read_jpeg(char *path)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * infile;
int row_stride;
unsigned char *buffer;



// 分配和初始化一个decompression结构体
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);


// 指定源文件
if ((infile = fopen(path, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", path);
return NULL;
}
jpeg_stdio_src(&cinfo, infile);
// 用jpeg_read_header获得jpg信息
jpeg_read_header(&cinfo, TRUE);
/* 源信息 */
#if 0
printf("image_width = %d\n", cinfo.image_width);
printf("image_height = %d\n", cinfo.image_height);
printf("num_components = %d\n", cinfo.num_components);


// 设置解压参数,比如放大、缩小
printf("enter scale M/N:\n");
//anf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);
printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);
#endif
// 启动解压:jpeg_start_decompress
jpeg_start_decompress(&cinfo);
#if 0
/* 输出的图象的信息 */
printf("output_width = %d\n", cinfo.output_width);
printf("output_height = %d\n", cinfo.output_height);
printf("output_components = %d\n", cinfo.output_components);
#endif
width_bmp= cinfo.output_width;
height_bmp = cinfo.output_height;

// 一行的数据长度
row_stride = cinfo.output_width * cinfo.output_components;
buffer = malloc(row_stride);
unsigned char *image= (unsigned char*)malloc(cinfo.output_width* cinfo.output_height*2);//一个颜色点16位两个字节
unsigned short short_buf;
int curr_y = 0;
int curr_x = 0;
int jpeg_x=0;
int location;
// 循环调用jpeg_read_scanlines来一行一行地获得解压的数据
while (cinfo.output_scanline < cinfo.output_height) 
{
location =curr_x*2 + cinfo.output_width*2*curr_y;
(void) jpeg_read_scanlines(&cinfo, &buffer, 1);
while(curr_x < cinfo.output_width)
{
short_buf=(((*(buffer+jpeg_x)&0xf8)>>3)<<11)|(((*(buffer+jpeg_x+1)&0xfc) >> 2) << 5) | ((*(buffer+jpeg_x+2)&0xf8) >> 3);

*(image + location + 0) = (char)(short_buf&0xff);
*(image + location + 1) = (char)((short_buf&0xff00) >> 8);
jpeg_x = jpeg_x+3;
curr_x++;//当前是那个像素点,bits_per_pixel/8是每个像素占多少位字节
location =curr_x*2 + cinfo.output_width*2*curr_y;
}
curr_y++;
curr_x = 0;
jpeg_x = 0;
}


free(buffer);
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return image;
}


//这是主函数,图片的输入路径由main函数的第一个参数决定
int main(char argv, char **argc)
{

if(argv != 2)
{
printf("input fine err!\nplease input pic file\n");
return 0;
}
/* 初始化framebuffer */
initFramebuffer();
printf("file:%s\n",argc[1]);
unsigned char *image = read_picture(argc[1]);
write_buf_image(image,0,0,width_bmp,height_bmp); /*往framebuffer里面写数据,显示到LCD上面去*/
return 0;
}

你可能感兴趣的:(C语言实现的BMP和JPEG图片的解码)