clang jpeg


原文链接: clang jpeg
/*
这是read_picture.c 文件的代码 ,主要是对输入的图片的文件(BMP和JPEG类型)进行解码,转换成在LCD中显示的数据;
使用该程序时,要先把jpeglib库文件和头文件放到对应的标谁库和标准头文件中;否则编译出错的
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>

#include "jpeglib.h"
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>

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);
}


unsigned char *jpeg_info(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

	width_bmp = cinfo.output_width;
	height_bmp = cinfo.output_height;

}
/*
这是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;
}

————————————————
版权声明:本文为CSDN博主「YANGSENG1987」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/YANGSENG1987/article/details/9770663

`