您的位置:首页 > 运维架构 > Linux

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

2016-05-26 12:51 513 查看
目前只支持jpeg格式的图片,需要显示其他图片的在main函数中添加就可以。解析出图片头字节,根据字节判断是属于什么格式的图片。

有四个文件:main.c  input_manager.c   touchscreen.c    input_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_STDIN 0
#define INPUT_TYPE_TOUCHSCREEN 1

#define INPUT_VALUE_UP 1
#define INPUT_VALUE_DOWN 2
#define INPUT_VALUE_EXIT 3
#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;
}


下一篇文章讲解图片的缩放合并算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: