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