📄 showimg.c
字号:
/*
showimg.c
*/
#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 <sys/types.h>
#include <jpeglib.h>
#include <setjmp.h>
int image_height;
int image_width;
JSAMPLE image_buffer[320][720];
struct my_error_mgr {
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
//14byte
typedef struct
{
char cfType[2]; /* 文件类型, 必须为 "BM" (0x4D42)*/
char cfSize[4]; /* 文件的大小(字节) */
char cfReserved[4]; /* 保留, 必须为 0 */
char cfoffBits[4]; /* 位图阵列相对于文件头的偏移量(字节)*/
}__attribute__((packed)) BITMAPFILEHEADER; /* 文件头结构 *///__attribute__((packed))作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
//40byte
typedef struct
{
char ciSize[4]; /* size of BITMAPINFOHEADER */
char ciWidth[4]; /* 位图宽度(像素) */
char ciHeight[4]; /* 位图高度(像素) */
char ciPlanes[2]; /* 目标设备的位平面数, 必须置为1 */
char ciBitCount[2]; /* 每个像素的位数, 1,4,8或24 */
char ciCompress[4]; /* 位图阵列的压缩方法,0=不压缩 */
char ciSizeImage[4]; /* 图像大小(字节) */
char ciXPelsPerMeter[4];/* 目标设备水平每米像素个数 */
char ciYPelsPerMeter[4];/* 目标设备垂直每米像素个数 */
char ciClrUsed[4]; /* 位图实际使用的颜色表的颜色数 */
char ciClrImportant[4]; /* 重要颜色索引的个数 */
}__attribute__((packed)) BITMAPINFOHEADER; /* 位图信息头结构 */
typedef struct
{
unsigned short blue:5; //每个颜色均用5位表示,X R R R R R G G G G G B B B B B (X表示不用,可以忽略)高字节,低字节
unsigned short green:5;
unsigned short red:5;
unsigned short rev:1;
}__attribute__((packed)) RGB555;
typedef struct
{
unsigned short blue:5; //R R R R R G G G G G G B B B B B
unsigned short green:6;
unsigned short red:5;
}__attribute__((packed)) RGB565;
typedef struct
{
unsigned short blue:8; //内存中RGB各分量的排列顺序为:BGR BGR
unsigned short green:8;
unsigned short red:8;
}__attribute__((packed)) RGB888;
BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;
char *fbp = 0;
int xres = 0;
int yres = 0;
int bits_per_pixel = 0;
int show_bmp ( char *bmpfile );
long chartolong ( char * string, int length );
/******************************************************************************
*
******************************************************************************/
int main ( int argc, char *argv[] )
{
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd)
{
printf("Error cannot open framebuffer device.\n");
exit(1);
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
printf("Error reading variable information.\n");
exit(3);
}
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
xres = vinfo.xres;
yres = vinfo.yres;
bits_per_pixel = vinfo.bits_per_pixel;
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fbfd, 0);
if ((int)fbp == -1)
{
printf("Error failed to map framebuffer device to memory.\n");
exit(4);
}
printf("sizeof header=%d\n", sizeof(BITMAPFILEHEADER));
printf("into show_bmp fun\n");
show_img( argv[1] );
munmap(fbp, screensize);
close(fbfd);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int show_img( char *imgfile )
{
FILE *fp;
//int RGBflag;
int rc;
int ciBitCount, ciWidth, ciHeight;
int line_x, line_y;
long int location = 0, BytesPerLine = 0;
char tmp[1024*10];
if(is_bmp(imgfile))
{
/* 打开位图文件 */
fp = fopen( imgfile, "rb" );
if (fp == NULL)
{
return( -1 );
}
/* 读取位图文件头 */
rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp ); //读位图文件头到FileHead中
if ( rc != 1)
{
printf("read header error!\n");
fclose( fp );
return( -2 );
}
/* 判断位图的类型 */
if (memcmp(FileHead.cfType, "BM", 2) != 0)
{
printf("it's not a BMP file\n");
fclose( fp );
return( -3 );
}
/* 读取位图信息头 */
rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );//fread(buffer,size,count,fp),size:要读写的字节数;count:要进行读写多少个size字节的数据项;
if ( rc != 1)
{
printf("read infoheader error!\n");
fclose( fp );
return( -4 );
}
ciWidth = (int) chartolong( InfoHead.ciWidth, 4 ); //InfoHead.ciWidth,为一个字符串,得到图像的实际宽度
ciHeight = (int) chartolong( InfoHead.ciHeight, 4 ); //实际的高度
ciBitCount = (int) chartolong( InfoHead.ciBitCount, 4 ); //每像素的实际位数
fseek(fp, (int)chartolong(FileHead.cfoffBits, 4), SEEK_SET); //读偏移量,取得图像数据的实际位置
BytesPerLine = (ciWidth * ciBitCount + 31) / 32 * 4; //因为存储时要按四位对齐,也就是32位,技巧在意若ciWidth * ciBitCount为32的整数倍,则结果为ciWidth * ciBitCount/32,否则为ciWidth * ciBitCount/32+1;
printf("width=%d, height=%d, bitCount=%d, offset=%d\n", ciWidth, ciHeight, ciBitCount, (int)chartolong(FileHead.cfoffBits, 4));
line_x = line_y = 0;
while(!feof(fp)) //检测流上的文件结束符,如果遇到文件结束,函数feof(fp)的值为1,否则为0
{
unsigned short int tmp;
unsigned short int red,green,blue;
if( ciBitCount==16)
{
RGB555 pix16;
//unsigned short RGB555;
rc = fread( (char *)&pix16, 1,2, fp ); //完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
if (rc != 2 )
{ break; }
tmp=pix16.red<<11 | pix16.green<<6 | pix16.blue;
}
if( ciBitCount==24)
{
RGB888 pix24;
//unsigned short RGB888;;
rc = fread((char *)&pix24, 1,3, fp ); //完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
if (rc != 3)
{ break; }
red=(pix24.red&0xF8)<<8;
green=(pix24.green&0xFA)<<3;
blue=(pix24.blue&0xF8)>>3;
tmp=red|green|blue;
}
location = line_x * bits_per_pixel / 8 + (ciHeight - line_y - 1) * xres * bits_per_pixel / 8;
*((unsigned short int*)(fbp + location)) = tmp; //bmp的数据是倒序,从左下角开始。给出了两个指针相加的范例。
line_x++;
if (line_x == ciWidth )
{
line_x = 0;
line_y++;
if(line_y==ciHeight-1)
{
break;
}
}
}
fclose( fp );
}
if(is_jpg(imgfile))
{
unsigned short int tmp;
unsigned short int red,green,blue;
read_jpeg_file(imgfile);
for(line_x=0;line_x< ciWidth;line_x++)
{
for(line_y=0;line_y<ciHeight;line_y++)
{
red=(image_buffer[line_x][3*line_y]&0xF8)<<8;
green=(image_buffer[line_x][3*line_y+1]&0xFA)<<3;
blue=(image_buffer[line_x][3*line_y+2]&0xF8)>>3;
tmp=red|green|blue;
location = line_y * bits_per_pixel / 8 + line_x * xres * bits_per_pixel / 8;
*((unsigned short int*)(fbp + location)) = tmp;
}
}
}
else printf("can't display format");
return( 0 );
}
/******************************************************************************
*
******************************************************************************/
long chartolong( char * string, int length ) //将4个字符串类的数据合并成一个long型变量
{
long number;
if (length <= 4)
{
memset( &number, 0x00, sizeof(long) );
memcpy( &number, string, length );
}
return( number );
}
/******************************************************************************
*判断一个文件是jpeg格式还是bmp格式
******************************************************************************/
static int is_bmp (char *filename)
{
int length = strlen (filename);
if (filename[length-4] != '.')
{
return 0;
}
if ((filename[length-3] != 'b') && (filename[length-3] != 'B'))
{
return 0;
}
if ((filename[length-2] != 'm') && (filename[length-2] != 'M'))
{
return 0;
}
if ((filename[length-1] != 'p') && (filename[length-1] != 'P'))
{
return 0;
}
return 1;
}
static int is_jpg (char *filename)
{
int length = strlen (filename);
if (filename[length-4] != '.')
{
return 0;
}
if ((filename[length-3] != 'j') && (filename[length-3] != 'J'))
{
return 0;
}
if ((filename[length-2] != 'p') && (filename[length-2] != 'P'))
{
return 0;
}
if ((filename[length-1] != 'g') && (filename[length-1] != 'G'))
{
return 0;
}
return 1;
}
/******************************************************************************
*对jpeg格式代码进行解码
******************************************************************************/
METHODDEF(void)my_error_exit (j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr) cinfo->err;
(*cinfo->err->output_message) (cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
int read_jpeg_file(char * filename)
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE * infile; /* source file */
JSAMPARRAY buffer; /* Output row buffer */
int row_stride; /* physical row width in output buffer */
int i;
infile=fopen(filename,"rb");
if (infile == NULL)
{
fprintf (stderr, "can't open %s\n", filename);
exit(1);
}
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void) jpeg_read_header(&cinfo, TRUE);
(void) jpeg_start_decompress(&cinfo);
/* row_stride = cinfo.output_width * cinfo.output_components; */
row_stride=image_width*3;
buffer = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
for(i=0;i<image_height;i++) {
(void) jpeg_read_scanlines(&cinfo,buffer,1);
memcpy(image_buffer[i],buffer[0],row_stride);
}
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -