歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> Linux應用編程之圖片浏覽APP實現

Linux應用編程之圖片浏覽APP實現

日期:2017/3/3 12:22:44   编辑:Linux技術

目前只支持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;
}
下一篇文章講解圖片的縮放合並算法。

Copyright © Linux教程網 All Rights Reserved