现在的位置: 首页 > 综合 > 正文

触摸校验添加图片 framerbuff 显示bmp图片

2013年12月12日 ⁄ 综合 ⁄ 共 10609字 ⁄ 字号 评论关闭

framerbuff 显示bmp图片需要注意的两个地方:

1. 图片颜色的处理,需要改动的地方: red=(pix24.red&0xF8)<<8;  green=(pix24.green&0xFC)<<3;   blue=(pix24.blue&0xF8)>>3;
2. 如果图片发现倾斜应该是图片尺寸不对,截取的图片大小,最好是8的倍数(宽度)。

源码如下:(有不对之处还请指正)

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <arpa/inet.h>

#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <errno.h>
#include <sys/reboot.h>
#include <linux/serio.h>

#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/fb.h>

#define DEFAULT_PROTO 0x40
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;

//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 short blue;
unsigned short green;
unsigned short red;
unsigned short reserved;
}__attribute__((packed)) PIXEL;//颜色模式RGB

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;

static char *fbp = 0;

int show_bmp(int x,int y)
{
FILE *fp;
int rc;
int ciBitCount, ciWidth, ciHeight;
int line_x, line_y;
long int location = 0, BytesPerLine = 0;
char tmp[1024*10];
static int a=0;

fp = fopen( "/usr/bin/niu.bmp", "rb" );
if (fp == NULL)
{
return( -1 );
}

rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );
if ( rc != 1)
{
printf("read header error!\n");
fclose( fp );
return( -2 );
}

//检测是否是bmp图像
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 );
if ( rc != 1)
{
printf("read infoheader error!\n");
fclose( fp );
return( -4 );
}

fseek(fp, FileHead.cfoffBits, SEEK_SET); //读偏移量,取得图像数据的实际位置
BytesPerLine = (InfoHead.ciWidth * InfoHead.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", InfoHead.ciWidth, InfoHead.ciHeight, InfoHead.ciBitCount,FileHead.cfoffBits);
line_x =0;line_y =0;

while(!feof(fp)) //检测流上的文件结束符,如果遇到文件结束,函数feof(fp)的值为1,否则为0
{
unsigned short int tmp1;
unsigned short int red,green,blue;

if( InfoHead.ciBitCount==16)
{
RGB555 pix16;
//unsigned short RGB555;
rc = fread( (char *)&pix16, 1,2, fp ); //完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
if (rc != 2 )
{ break; }
tmp1=pix16.red<<11 | pix16.green<<6 | pix16.blue;

}

if( InfoHead.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&0xFC)<<3;
blue=(pix24.blue&0xF8)>>3;
tmp1=red|green|blue;

}

//location = (100+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +(100+vinfo.yoffset) * finfo.line_length;

//location = (x+line_x) *vinfo.bits_per_pixel / 8 + (InfoHead.ciHeight - line_y - 1+y) * vinfo.xres * vinfo.bits_per_pixel / 8;

location = (x+line_x) *vinfo.bits_per_pixel / 8 + (InfoHead.ciHeight+y-line_y-1) * vinfo.xres * vinfo.bits_per_pixel / 8;

*((unsigned short int*)(fbp + location)) = tmp1; //bmp的数据是倒序,从左下角开始。给出了两个指针相加的范例。

line_x++;
if (line_x == InfoHead.ciWidth )
{
line_x = 0;
line_y++;
if(line_y==InfoHead.ciHeight-1)
{
break;
}
}
}
fclose( fp );
#endif
return( 0 );
}

static int open_touchscreen_serial(char *dev_name)
{
int serial_fd = -1;
char *serial_name=NULL;
struct termios opt;

if(dev_name){
serial_name=dev_name;
}else{
serial_name = getenv("TSLIB_SERIAL_NODE");
}
serial_fd = open(serial_name, O_RDWR | O_NOCTTY);
if(serial_fd<=0){
printf("open serial %s failure.\n",serial_name);
return -1;
}
tcgetattr(serial_fd, &opt);
cfsetispeed(&opt, B9600);
cfsetospeed(&opt, B9600);
if(tcsetattr(serial_fd, TCSANOW, &opt) != 0){
printf("tcsetattr error.\n");
return -2;
}
opt.c_cflag &= ~(CSIZE|PARENB);
opt.c_cflag |= CS8;
opt.c_cflag&=~PARENB;
opt.c_iflag&=~INPCK;
opt.c_cflag&=~CSTOPB;
opt.c_cc[VTIME] = 30;
opt.c_cc[VMIN] = 0;
opt.c_cflag&=(~CRTSCTS);
//set Raw Mode
opt.c_lflag&=~(ICANON | ECHO | ECHOE | ISIG);
opt.c_oflag&=~OPOST;
//clear Software Flow Control
opt.c_iflag &= ~(IXON | IXOFF | IXANY);
//clear 0x0d and 0x0a map
opt.c_oflag &= ~(ONLCR | OCRNL);
opt.c_iflag &= ~(INLCR | ICRNL);
if (tcsetattr(serial_fd, TCSANOW,&opt)!=0){
return 0;
}
tcflush(serial_fd,TCIOFLUSH);
return serial_fd;
}

static void drawline_hor(char *abase,int xo,int xe,int y)
{
long int location = 0;
int x;
unsigned short int color = 0xFFFF;
for(x=xo;x<=xe;x++)
{
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(abase + location))=color;
}
}

static void drawline_ver(char *abase,int yo,int ye,int x)
{
long int location = 0;
int y;
unsigned short int color = 0xFFFF;
for(y=yo;y<=ye;y++)
{
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +(y+vinfo.yoffset) * finfo.line_length;
*((unsigned short int*)(abase + location))=color;
}
}
static void cleanscreen(char *abase)
{
int x,y;
long int location = 0;
for (y = 0; y < vinfo.yres; y++)
{
for (x = 0; x < vinfo.xres; x++)
{
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +(y+vinfo.yoffset) * finfo.line_length;
if (vinfo.bits_per_pixel == 32)
{
*(abase + location) = 0x00; // blue
*(abase + location + 1) = 0x00; // green
*(abase + location + 2) = 0x00; // red
*(abase + location + 3) = 0x00; // no transparency
}
else
{
int b = 0;
int g = 0;
int r = 0;
unsigned short int t = r<<11 | g << 5 | b;
*((unsigned short int*)(abase + location)) = t;
}
}
}
}

int raw_calibrate_touchscreen(char *device_name){
int fb_fd = 0,serial_fd=0;
char serbuf[10];
int ret=-1;
int first_x,first_y,second_x,second_y;
long int screensize = 0;
//char *fbp = 0;

fb_fd = open("/dev/fb0", O_RDWR); // Open the file for reading and writing
if (fb_fd<=0)
{
printf("Error: cannot open framebuffer device.\n");
return -1;
}
//printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if(ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo))
{
printf("Error reading fixed information.\n");
close(fb_fd);
return -2;
}
// Get variable screen information
if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo))
{
printf("Error reading variable information.\n");
close(fb_fd);
return -3;
}
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, 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, fb_fd, 0);
if((int)fbp == -1)
{
printf("Error: failed to map framebuffer device to memory.\n");
close(fb_fd);
return -4;
}
cleanscreen(fbp);
serial_fd=open_touchscreen_serial(device_name);
if(serial_fd<=0)
{
close(fb_fd);
return -1;
}

memset(serbuf,0x00,sizeof(serbuf));
serbuf[0]=0x90;
write(serial_fd,serbuf,1);
first_x = vinfo.xres / 8;
first_y = vinfo.yres / 8;
#if 0
drawline_hor(fbp,first_x-10,first_x+10,first_y);
drawline_ver(fbp,first_y-10,first_y+10,first_x);
#else

show_bmp(65,120);

drawline_hor(fbp,first_x-10,first_x-10+4,first_y-10);
drawline_hor(fbp,first_x+10-4,first_x+10,first_y-10);
drawline_hor(fbp,first_x-10,first_x-10+4,first_y+10);
drawline_hor(fbp,first_x+10-4,first_x+10,first_y+10);
drawline_hor(fbp,first_x-10,first_x-1,first_y);
drawline_hor(fbp,first_x+1,first_x+10,first_y);

drawline_ver(fbp,first_y-10,first_y-10+4,first_x-10);
drawline_ver(fbp,first_y+10-4,first_y+10,first_x-10);
drawline_ver(fbp,first_y-10,first_y-10+4,first_x+10);
drawline_ver(fbp,first_y+10-4,first_y+10,first_x+10);
drawline_ver(fbp,first_y-10,first_y-1,first_x);
drawline_ver(fbp,first_y+1,first_y+10,first_x);

#endif
while(1)
{
ret=read(serial_fd,serbuf,1);
if(ret>0){
printf("recive data length:%d 0x%x\n",ret,serbuf[0]);
if(serbuf[0]==0x91)
break;
}
}
cleanscreen(fbp);
second_x = vinfo.xres*7 / 8;
second_y = vinfo.yres*7 / 8;
#if 0
drawline_hor(fbp,second_x-10,second_x+10,second_y);
drawline_ver(fbp,second_y-10,second_y+10,second_x);
#else
drawline_hor(fbp,second_x-10,second_x-10+4,second_y-10);

drawline_hor(fbp,second_x+10-4,second_x+10,second_y-10);
drawline_hor(fbp,second_x-10,second_x-10+4,second_y+10);
drawline_hor(fbp,second_x+10-4,second_x+10,second_y+10);
drawline_hor(fbp,second_x-10,second_x-1,second_y);
drawline_hor(fbp,second_x+1,second_x+10,second_y);

drawline_ver(fbp,second_y-10,second_y-10+4,second_x-10);
drawline_ver(fbp,second_y+10-4,second_y+10,second_x-10);
drawline_ver(fbp,second_y-10,second_y-10+4,second_x+10);
drawline_ver(fbp,second_y+10-4,second_y+10,second_x+10);
drawline_ver(fbp,second_y-10,second_y-1,second_x);
drawline_ver(fbp,second_y+1,second_y+10,second_x);

show_bmp(835,620);
#endif
while(1)
{
ret=read(serial_fd,serbuf,1);
if(ret>0){
printf("recive extra data length:%d 0x%x\n",ret,serbuf[0]);
if(serbuf[0]==0x92)
break;
}
}
cleanscreen(fbp);
munmap(fbp, screensize);
close(serial_fd);
close(fb_fd);
printf("calibration finished...\n");
return 0;
}

int change_serio_bus(char *device_name,unsigned int proto,unsigned int id,unsigned int extra){
int serial_fd=-1;
int ret=-1;
unsigned long int devt=0;
unsigned long int ldisc=N_MOUSE;
pid_t input_pid;
if((input_pid=fork())>0){
exit(0);
}else if(input_pid==0){ //th1 child
setsid(); //th1鏄垚涓轰細璇濇湡缁勯暱
serial_fd = open_touchscreen_serial(device_name);
if(serial_fd<=0)
{
printf("change to serio bus error\n");
return -1;
}
if (ioctl(serial_fd, TIOCSETD, &ldisc)) {
printf("inputattach: can't set line discipline\n");
close(serial_fd);
return -2;
}
devt = proto | (id << 8) | (extra << 16);
if (ioctl(serial_fd, SPIOCSTYPE, &devt)) {
fprintf(stderr, "inputattach: can't set device type\n");
close(serial_fd);
return -3;
}
ret=read(serial_fd, NULL,0);
close(serial_fd);
return 0;
}else{
perror("fork:");
return -1;
}
return 0;
}

void help_msg(){
printf("------------------------------------------------------------\n"
"| Usage: sch_utils\n"
"| ===============\n"
"| -d [serial name]\n"
"| -c [calibrate touch screen raw]\n"
"| -h [help info]\n"
"------------------------------------------------------------\n");
}

int main(int argc,char *argv[])
{
int ret=-1;
int c=0;
int calibrate_flag=0;
char *device_name=NULL;

while ((c = getopt(argc, argv,"cd:h")) != -1) {
switch (c) {
case 'c':
calibrate_flag=1;
break;
case 'd':
device_name=optarg;
break;
case 'h':
help_msg();
return 0;
break;
default:
printf("invalid argument: optarg[%s]\n", optarg);
help_msg();
return 0;
break;
}
}

if(calibrate_flag){
printf("open serila name:%s \n", device_name);
ret=raw_calibrate_touchscreen(device_name);

}else{
ret=change_serio_bus(device_name,DEFAULT_PROTO,0xFF,0xFF);
}
return ret;
}

抱歉!评论已关闭.