红联Linux门户
Linux帮助

Linux应用编程之图片浏览APP实现

发布时间:2016-09-13 10:43:33来源:qq_21792169作者:Linux_Google
目前只支持jpeg格式的图片,需要显示其他图片的在main函数中添加就可以。解析出图片头字节,根据字节判断是属于什么格式的图片。
有四个文件:main.c input_manager.c  touchscreen.cinput_manager.h编译时候加上-ljpeg -lts -lpthread库。
 
main.c文件:
#include <stdio.h>  
#include <jpeglib.h>  
#include <setjmp.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include <sys/mman.h>  
#include <linux/fb.h>  
#include <string.h>  
#include <stdlib.h>  
#include <tslib.h>  
#include <dirent.h>  
#include <string.h>  
#include <unistd.h>  
#include <input_manager.h>   
#define FB_DEVICE_NAME "/dev/fb0"   
//#define DBG_PRINTF(...)
#define DBG_PRINTF printf  
#define FILE_PATH  "/tmp/digitpic/icons_jpeg"  
static int g_fd;  
static struct fb_var_screeninfo g_tFBVar;  
static struct fb_fix_screeninfo g_tFBFix; 
static unsigned char *g_pucFBMem;  
static unsigned int g_dwScreenSize;  
static unsigned int g_dwLineWidth;  
static unsigned int g_dwPixelWidth;   
static int FBDeviceInit(void)  
{  
int ret;  
g_fd = open(FB_DEVICE_NAME, O_RDWR);  
if (0 > g_fd)  
{  
DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);  
}  
ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar);  
if (ret < 0)  
{  
DBG_PRINTF("can't get fb's var\n");  
return -1;  
}  
ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);  
if (ret < 0)  
{  
DBG_PRINTF("can't get fb's fix\n");  
return -1;  
}  
g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;  
g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0);  
if (0 > g_pucFBMem)
{  
DBG_PRINTF("can't mmap\n");  
return -1;  
}  
g_dwLineWidth  = g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8;  
g_dwPixelWidth = g_tFBVar.bits_per_pixel / 8;  
return 0;  
}  
static int FBShowPixel(int iX, int iY, unsigned int dwColor)  
{  
unsigned char *pucFB;  
unsigned short *pwFB16bpp;  
unsigned int *pdwFB32bpp;  
unsigned short wColor16bpp; /* 565 */  
int iRed;  
int iGreen;  
int iBlue;  
if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))  
{  
DBG_PRINTF("out of region\n");  
return -1;  
pucFB  = g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX;  
pwFB16bpp  = (unsigned short *)pucFB;  
pdwFB32bpp = (unsigned int *)pucFB;  
switch (g_tFBVar.bits_per_pixel)  
{  
case 8:  
{  
*pucFB = (unsigned char)dwColor;  
break;  
}  
case 16:  
{  
iRed   = (dwColor >> (16+3)) & 0x1f;  
iGreen = (dwColor >> (8+2)) & 0x3f;  
iBlue  = (dwColor >> 3) & 0x1f;  
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;  
*pwFB16bpp  = wColor16bpp;  
break;  
}  
case 32:  
{  
*pdwFB32bpp = dwColor;  
break;  
}  
default :  
{  
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);  
return -1;  
}  
}  
return 0;  
}  
static int FBCleanScreen(unsigned int dwBackColor)  
{  
unsigned char *pucFB;  
unsigned short *pwFB16bpp;  
unsigned int *pdwFB32bpp;  
unsigned short wColor16bpp; /* 565 */  
int iRed;  
int iGreen;  
int iBlue;  
int i = 0;  
pucFB  = g_pucFBMem;  
pwFB16bpp  = (unsigned short *)pucFB;  
pdwFB32bpp = (unsigned int *)pucFB;  
switch (g_tFBVar.bits_per_pixel)  
{  
case 8:  
{  
memset(g_pucFBMem, dwBackColor, g_dwScreenSize);  
break;  
}  
case 16:  
{  
iRed   = (dwBackColor >> (16+3)) & 0x1f;  
iGreen = (dwBackColor >> (8+2)) & 0x3f;  
iBlue  = (dwBackColor >> 3) & 0x1f;  
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;  
while (i < g_dwScreenSize)  
{  
*pwFB16bpp  = wColor16bpp;  
pwFB16bpp++;  
i += 2;  
}  
break;  
}  
case 32:  
{  
while (i < g_dwScreenSize)  
{  
*pdwFB32bpp = dwBackColor;  
pdwFB32bpp++;  
i += 4;  
}  
break;  
}  
default :  
{  
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);  
return -1;  
}  
}  
return 0;  
}  
static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray)  
{  
int i = iXStart * 3;  
int iX;  
unsigned int dwColor;  
if (iY >= g_tFBVar.yres)  
return -1;  
if (iXStart >= g_tFBVar.xres)  
return -1;  
if (iXEnd >= g_tFBVar.xres)  
{  
iXEnd = g_tFBVar.xres;
}  
for (iX = iXStart; iX < iXEnd; iX++)  
{  
/* 0xRRGGBB */  
dwColor = (pucRGBArray[i]<<16) + (pucRGBArray[i+1]<<8) + (pucRGBArray[i+2]<<0);  
i += 3;  
FBShowPixel(iX, iY, dwColor);  
}  
return 0;  
}  
static int show_jpeg_file(char *file_name)  
{  
struct jpeg_decompress_struct cinfo;  
struct jpeg_error_mgr jerr;  
FILE * infile;  
int row_stride;  
unsigned char *buffer;  
int  Width,Height,temp;  
// 分配和初始化一个decompression结构体  
cinfo.err = jpeg_std_error(&jerr);  
jpeg_create_decompress(&cinfo);  
// 指定源文件  
if ((infile = fopen(file_name, "rb")) == NULL) {  
fprintf(stderr, "can't open %s\n",file_name);  
return -1;  
}  
jpeg_stdio_src(&cinfo, infile);  
// 用jpeg_read_header获得jpg信息  
jpeg_read_header(&cinfo, TRUE);  
/* 源信息 */  
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");  
//scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);  //手动输入缩放比例,麻烦,下面给出自己计算  
//printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);  
Width  =cinfo.image_width;  
Height =cinfo.image_height;  
if((Width>420)||(Height>272))  /* 需要缩小 */  
{  
if(Width/Height>=(420/272))  /*以宽度为标准缩放*/  
{  
cinfo.scale_num=1;  
cinfo.scale_denom=Width/420;  
else   /*以高度为标准缩放*/  
{  
cinfo.scale_num=1;  
cinfo.scale_denom=Height/272;  
}  
}  
else   /* 保持图片原先大小 */  
{  
cinfo.scale_num=1;  
cinfo.scale_denom=1;   
}  
printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);  
// 启动解压:jpeg_start_decompress 
jpeg_start_decompress(&cinfo);  
/* 输出的图象的信息 */  
printf("output_width = %d\n", cinfo.output_width);  
printf("output_height = %d\n", cinfo.output_height);  
printf("output_components = %d\n", cinfo.output_components);  
// 一行的数据长度  
row_stride = cinfo.output_width * cinfo.output_components;  
buffer = malloc(row_stride);  
// 循环调用jpeg_read_scanlines来一行一行地获得解压的数据  
while (cinfo.output_scanline < cinfo.output_height)   
{  
(void) jpeg_read_scanlines(&cinfo, &buffer, 1);  
// 写到LCD去  
FBShowLine(0, cinfo.output_width, cinfo.output_scanline, buffer);  
}  
free(buffer);  
jpeg_finish_decompress(&cinfo);  
jpeg_destroy_decompress(&cinfo);  
return 0;  
}  
static struct dirent **namelist;   
static int  scandir_file()  
{   
int n;   
n = scandir(FILE_PATH, &namelist, NULL, alphasort);  
if (n < 0)  
{  
DBG_PRINTF("scandir  error\n");  
return -1;  
}  
return n;  
}  
/*  
Allocate and initialize a JPEG decompression object// 分配和初始化一个decompression结构体  
Specify the source of the compressed data (eg, a file) // 指定源文件  
Call jpeg_read_header() to obtain image info   // 用jpeg_read_header获得jpg信息  
Set parameters for decompression   // 设置解压参数,比如放大、缩小  
jpeg_start_decompress(...);// 启动解压:jpeg_start_decompress  
while (scan lines remain to be read)  
jpeg_read_scanlines(...);  // 循环调用jpeg_read_scanlines  
jpeg_finish_decompress(...);   // jpeg_finish_decompress  
Release the JPEG decompression object  // 释放decompression结构体  
*/  
/* Uage: jpg2rgb <jpg_file>  
*/  
int main(int argc, char **argv)  
{  
int file_all_num;  
int file_num=2;  
int i;  
char strTmp[256];  
int iError;  
T_InputEvent tInputEvent;  
iError=InputInit();  
if (iError)  
{  
DBG_PRINTF("InputInit error!\n");  
return -1;  
iError=AllInputDevicesInit();  
if (iError)  
{  
DBG_PRINTF("InputInit error!\n");  
return -1;  
}  
iError=FBDeviceInit();  
if (iError)  
{  
DBG_PRINTF("InputInit error!\n");  
return -1;  
file_all_num=scandir_file();  
for(i=0;i<file_all_num;i++)  
printf("file_all_num=%d,namelist[%d]->d_name=%s\n",file_all_num,i,namelist[i]->d_name);  
snprintf(strTmp, 256, "%s/%s",FILE_PATH, namelist[file_num]->d_name);  
strTmp[255] = '\0';  
DBG_PRINTF("strTmp=%s,file_num=%d\n",strTmp,file_num);  
FBCleanScreen(0);  
show_jpeg_file(strTmp);  
while(1)  
{  
if (0 == GetInputEvent(&tInputEvent));  
{  
usleep(100000);/* delay  */  
DBG_PRINTF("tInputEvent.iVal=%d\n",tInputEvent.iVal);  
if (tInputEvent.iVal == INPUT_VALUE_DOWN)  
{  
file_num++;   
if(file_num>=file_all_num)  
file_num=2;  
while((0 == strcmp(namelist[file_num]->d_name, ".")) || (0 == strcmp(namelist[file_num]->d_name, "..")))  
{  
file_num++;  
}  
}  
else if (tInputEvent.iVal == INPUT_VALUE_UP)  
{  
file_num--;   
if(file_num<0)  
file_num=file_all_num-1;  
while ((0 == strcmp(namelist[file_num]->d_name, ".")) || (0 == strcmp(namelist[file_num]->d_name, "..")))  
{  
file_num=file_all_num-1;  
}  
}  
else   
{  
FBCleanScreen(0);  
return -1;  
}  
snprintf(strTmp, 256, "%s/%s",FILE_PATH, namelist[file_num]->d_name);  
strTmp[255] = '\0';  
DBG_PRINTF("strTmp=%s,file_num=%d\n",strTmp,file_num);  
FBCleanScreen(0);  
show_jpeg_file(strTmp);  
}  
}  
return 0;  
}
 
input_manager.h文件:
#ifndef _INPUT_MANAGER_H  
#define _INPUT_MANAGER_H  
#include <sys/time.h>  
#include <pthread.h>  
#define INPUT_TYPE_STDIN0  
#define INPUT_TYPE_TOUCHSCREEN  1  
#define INPUT_VALUE_UP  1
#define INPUT_VALUE_DOWN2  
#define INPUT_VALUE_EXIT3  
#define INPUT_VALUE_UNKNOWN -1  
typedef struct InputEvent {  
struct timeval tTime;  
int iType;  /* stdin, touchsceen */  
int iVal;   /*  */  
}T_InputEvent, *PT_InputEvent;  
typedef struct InputOpr {  
char *name;  
pthread_t tTreadID;  
int (*DeviceInit)(void);  
int (*DeviceExit)(void);  
int (*GetInputEvent)(PT_InputEvent ptInputEvent);  
struct InputOpr *ptNext;  
}T_InputOpr, *PT_InputOpr;  
int InputInit(void);  
int RegisterInputOpr(PT_InputOpr ptInputOpr);  
void ShowInputOpr(void);  
int AllInputDevicesInit(void);  
int GetInputEvent(PT_InputEvent ptInputEvent);  
int TouchScreenInit(void);  
#endif /* _INPUT_MANAGER_H */  
 
touchscreen.c文件:
#include <input_manager.h>  
#include <stdlib.h>  
#include <tslib.h>  
#define DBG_PRINTF(...)
/* 参考tslib里的ts_print.c */  
static struct tsdev *g_tTSDev;  
static int giXres=420;  
static int giYres=272;  
/* 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后调用 */  
static int TouchScreenDevInit(void)  
{  
char *pcTSName = NULL;  
if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL )   
{  
g_tTSDev = ts_open(pcTSName, 0);  /* 以阻塞方式打开 */  
}  
else  
{  
g_tTSDev = ts_open("/dev/event0", 1);  
}  
if (!g_tTSDev) {  
DBG_PRINTF("ts_open error!\n");  
return -1;  
}  
if (ts_config(g_tTSDev)) {  
DBG_PRINTF("ts_config error!\n");  
return -1;  
}  
return 0;  
}  
static int TouchScreenDevExit(void)  
{  
return 0;  
}  
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)  
{  
struct ts_sample tSamp;  
int iRet;  
iRet = ts_read(g_tTSDev, &tSamp, 1); /* 如果无数据则休眠 */  
if (iRet < 0) {  
return -1;  
}  
/* 处理数据 */  
/* 如果此次触摸事件发生的时间, 距上次事件超过了500ms */  
ptInputEvent->tTime = tSamp.tv;  
ptInputEvent->iType = INPUT_TYPE_TOUCHSCREEN;  
if ((tSamp.y < giYres/3)||(tSamp.x < giXres/3))  
{  
ptInputEvent->iVal = INPUT_VALUE_UP;  
}  
else if ((tSamp.y > 2*giYres/3)||(tSamp.x > 2*giXres/3))  
{  
ptInputEvent->iVal = INPUT_VALUE_DOWN;  
}  
else  
{  
ptInputEvent->iVal = INPUT_VALUE_EXIT;  
}  
return 0;  
}  
static T_InputOpr g_tTouchScreenOpr = {  
.name  = "touchscreen",  
.DeviceInit= TouchScreenDevInit,  
.DeviceExit= TouchScreenDevExit,  
.GetInputEvent = TouchScreenGetInputEvent,  
};  
int TouchScreenInit(void)  
{  
return RegisterInputOpr(&g_tTouchScreenOpr);  
}  
 
input_manager.c文件:
#include <input_manager.h>  
#include <string.h>  
#define DBG_PRINTF printf  
static PT_InputOpr g_ptInputOprHead;  
static T_InputEvent g_tInputEvent;  
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;  
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;  
int RegisterInputOpr(PT_InputOpr ptInputOpr)  
{  
PT_InputOpr ptTmp;  
if (!g_ptInputOprHead)  
{  
g_ptInputOprHead   = ptInputOpr;  
ptInputOpr->ptNext = NULL;  
}  
else  
{  
ptTmp = g_ptInputOprHead;  
while (ptTmp->ptNext)  
{  
ptTmp = ptTmp->ptNext;  
}  
ptTmp->ptNext  = ptInputOpr;  
ptInputOpr->ptNext = NULL;  
}  
return 0;  
}  
void ShowInputOpr(void)  
{  
int i = 0;  
PT_InputOpr ptTmp = g_ptInputOprHead;  
while (ptTmp)  
{  
printf("%02d %s\n", i++, ptTmp->name);  
ptTmp = ptTmp->ptNext;  
}  
}  
static void *InputEventTreadFunction(void *pVoid)  
{  
T_InputEvent tInputEvent;  
/* 定义函数指针 */  
int (*GetInputEvent)(PT_InputEvent ptInputEvent);  
GetInputEvent = (int (*)(PT_InputEvent))pVoid;  
while (1)  
{  
if(0 == GetInputEvent(&tInputEvent))  
{  
/* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */  
/* 访问临界资源前,先获得互斥量 */  
pthread_mutex_lock(&g_tMutex);  
g_tInputEvent = tInputEvent;  
/*  唤醒主线程 */  
pthread_cond_signal(&g_tConVar);  
/* 释放互斥量 */  
pthread_mutex_unlock(&g_tMutex);  
}  
}  
return NULL;  
}  
int AllInputDevicesInit(void)  
{  
PT_InputOpr ptTmp = g_ptInputOprHead;  
int iError = -1;  
while (ptTmp)  
{  
if (0 == ptTmp->DeviceInit())  
{  
/* 创建子线程 */  
iError=pthread_create(&ptTmp->tTreadID, NULL, InputEventTreadFunction, ptTmp->GetInputEvent);   
if(iError ==0)  
{  
DBG_PRINTF("%s pthread_create  is succesd!\n",ptTmp->name);  
}  
}  
ptTmp = ptTmp->ptNext;  
}  
return iError;  
}  
int GetInputEvent(PT_InputEvent ptInputEvent)  
{  
/* 休眠 */  
pthread_mutex_lock(&g_tMutex);  
pthread_cond_wait(&g_tConVar, &g_tMutex); 
/* 被唤醒后,返回数据 */  
*ptInputEvent = g_tInputEvent;  
pthread_mutex_unlock(&g_tMutex);  
return 0; 
}  
int InputInit(void)  
{  
int iError;  
iError = TouchScreenInit();  
return iError;  
}
 
本文永久更新地址:http://www.linuxdiyf.com/linux/24119.html