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