1. 程式人生 > >圖片播放器(八):讀取資料夾中的圖片

圖片播放器(八):讀取資料夾中的圖片

採用連結串列的方式儲存圖片檔案的格式資訊,檔名和大小。

 

 

重要結構體:

/* 圖片檔案型別 */
typedef enum image_type
{
	IMAGE_TYPE_BMP,
	IMAGE_TYPE_JPG,
	IMAGE_TYPE_PNG,
	IMAGE_TPPE_UNKNOWN, /* 不能識別 */
}image_type_e;



/* 圖片檔案資訊 */
typedef struct iamge_file_info
{
	unsigned char       path_name[PATH_NAME_MAX];    /* 圖片檔案路徑 */
	image_type_e        image_type;                  /* 圖片檔案型別 */
	unsigned long int   picture_size;                /* 圖片檔案的大小 */
}iamge_file_info_s;


/* 檔案的雙向連結串列的節點 */
typedef struct iamge_file_node
{
    iamge_file_info_s       iamge_file_data;
    struct iamge_file_node *prior;
    struct iamge_file_node *next;
}iamge_file_node_s;

全域性變數和巨集定義:

#define PATH_NAME_MAX 256  /* 路徑名的最大位元組數 */
#define FILE_NODE_MAX 256  /* 連結串列節點數量最大值 */

iamge_file_node_s    file_head;                    /* 檔案頭連結串列頭 */
static unsigned int         now_file_num = 0;             /* 當前的圖片檔案數量 */
iamge_file_node_s          *tail_file_node = NULL;                /* 指向連結串列的尾節點*/

 

初始化:

功能:把所有的圖片加入到連結串列中

/* 初始化 */
int im_manage_init(void)
{
	const char path[PATH_NAME_MAX] = {"/usr/picture"};/* 所有圖片儲存這個資料夾下 */

	file_head.next = NULL;
	file_head.prior = NULL;
	
	im_add_dir(path);

	DEBUG("現在有 [%d] 張圖片\n", now_file_num);

	return 0;
}

path_name_dir 資料夾中的圖片檔案新增到連結串列中:

/* 把資料夾中的檔案新增到連結串列中 */
static int im_add_dir(const char *path_name_dir)
{
	DIR *dir = NULL;
	struct dirent *ptr;
	char base[PATH_NAME_MAX];
	struct stat sta;

	if((dir = opendir(path_name_dir)) == NULL)
	{
		DERROR("Open dir error...\n");
		return -1;
	}

	while ((ptr = readdir(dir)) != NULL)
	{
		if(strcmp(ptr->d_name, ".")==0 || strcmp(ptr->d_name, "..")==0)    ///current dir OR parrent dir
			continue;
	
			// 用lstat來讀取檔案屬性並判斷檔案型別
		memset(base,'\0',sizeof(base));
		strcpy(base,path_name_dir);
		strcat(base,"/");
		strcat(base,ptr->d_name);
		lstat(base, &sta);
	
		if (S_ISREG(sta.st_mode)){
			/* 新增普通檔案 */
			im_add_file(base);	
		}else if(S_ISDIR(sta.st_mode)){
			im_add_dir(base);/* 讀子資料夾 */
		}
	}

	return 0;
}

建立並初始化一個連結串列的節點:

/* 初始化一個連結串列的節點 */
static iamge_file_node_s *im_create_node(iamge_file_info_s *im_info_cr)
{
    iamge_file_node_s *p;
    p = (iamge_file_node_s*)malloc(sizeof(iamge_file_node_s));
    if(p == NULL){
        DERROR("動態記憶體分配失敗!\n");
        exit(-1);
    }

	p->iamge_file_data.image_type = im_info_cr->image_type;
	memset(p->iamge_file_data.path_name, 0, PATH_NAME_MAX);
	memcpy(p->iamge_file_data.path_name, im_info_cr->path_name, strlen((const char *)im_info_cr->path_name));
	p->iamge_file_data.picture_size = im_info_cr->picture_size;
    p->prior = NULL;
    p->next = NULL;
    return (p);
} 

新增檔案:

/* 新增檔案 */
int im_add_file(char *path_name_add)
{
	struct stat buffer;
	iamge_file_info_s  f_in;
	iamge_file_node_s *f_p = NULL;

	if(0 != lstat((const char *)path_name_add, &buffer)){
		DERROR("讀取檔案錯誤\n");
		return -1;
	}

	memset(f_in.path_name, 0, PATH_NAME_MAX);
	memcpy(f_in.path_name, path_name_add, strlen(path_name_add));

	if('Y' == im_is_bmp((const char *)path_name_add)){//判斷是否是bmp檔案
		f_in.image_type = IMAGE_TYPE_BMP;
	}else if('Y' == im_is_jpg((const char *)path_name_add)){
		f_in.image_type = IMAGE_TYPE_JPG;
	}else if('Y' == im_is_png((const char *)path_name_add)){
		f_in.image_type = IMAGE_TYPE_PNG;
	}else{
		f_in.image_type = IMAGE_TYPE_PNG;
	}

	f_in.picture_size = buffer.st_size;//賦值檔案的大小

	f_p = im_create_node(&f_in);//建立並初始化連結串列節點
	
	im_insert_list(f_p);//插入連結串列節點中

	return 0;
}

刪除檔案:

/* 刪除檔案 */
int im_remove_file(unsigned char *path_name_re)
{
	iamge_file_node_s *f_p = NULL;

	f_p = im_search_list(path_name_re);

	if(f_p == NULL){
		DERROR("沒有此檔案可以刪除\n");
		return -1;
	}

	if(im_delect_list(f_p) < 0){
		DERROR("刪除檔案失敗\n");
		return -1;
	}
	return 0;
}

在連結串列的頭部插入結點

/* 在連結串列的頭部插入結點 */
static void im_insert_list(iamge_file_node_s *file_node_in)
{
	if(file_head.next != NULL){
		file_head.next->prior = file_node_in;
		file_node_in->next = file_head.next;
	    file_head.next = file_node_in;
		file_node_in->prior = &file_head;
	}else{
		file_head.next = file_node_in;
		file_node_in->next = NULL;
		file_node_in->prior = &file_head;
		tail_file_node = file_node_in;
	}

	++now_file_num;
} 

刪除檔案結點:

/* 刪除檔案結點 */
static int im_delect_list(iamge_file_node_s *file_node_de)
{
    if(file_head.next == NULL){
        DERROR("現在播放器中沒有檔案\n");
		return -1;
	}else{
		if(file_node_de->next == NULL){
			file_node_de->prior->next = NULL;
			if(file_node_de->prior == &file_head){
				tail_file_node = NULL;
			}else{
				tail_file_node = file_node_de->prior;
			}
			file_node_de->prior = NULL;
		}else{
			file_node_de->prior->next = file_node_de->next;
			file_node_de->next->prior = file_node_de->prior;
			file_node_de->next = file_node_de->prior = NULL;
		}

		--now_file_num;
		free(file_node_de);
		return 0;
	}
} 

搜尋遍歷一個連結串列:

/* 搜尋遍歷一個連結串列 */
static iamge_file_node_s * im_search_list(unsigned char *path_name_se)
{
	iamge_file_node_s *p_file;

    if(file_head.next == NULL)
    {
        DERROR("現在播放器中沒有檔案\n");
		return NULL;
    }
    else
    {
        p_file = file_head.next;
        while(p_file != NULL)
        {
        	if(0 == memcmp(p_file->iamge_file_data.path_name, (const char *)path_name_se, strlen(((const char *)path_name_se)))){
				DEBUG("找到檔案 [%s]\n", path_name_se);
				return (p_file);

			}else{
				p_file = p_file->next;
			}
            
        }
		return NULL;
    }
} 

由於不想引用圖片顯示部分的函式,於是此檔案中定義了判斷檔案格式的函式:

/* 判斷是否為 bmp 檔案*/
static char im_is_bmp(const char *path)
{
	int ret;
	int fd = -1;
	char picture[2];

	if ((fd = open(path, O_RDONLY)) < 0 ){
		DERROR("NO [%s] file\n", path);
		return 'O';
	}

	if ((ret = read(fd, picture, 2)) < 2){
		DERROR("read [%s] file error\n", path);
		close(fd);
		return 'R';
	}

	if((picture[0] != 'B') || (picture[1] != 'M')){ /*判斷能前兩給位元組是否是 BM */
		DERROR("It's not a BMP file\n");
		close(fd);
		return 'N';
	}else{
		close(fd);
		return 'Y';
	}
}

/* 判斷是否為 jpg 檔案 */
static char im_is_jpg (const char *path)
{
	int ret;
	int fd = -1;
	char picture[2];

	if ((fd = open(path, O_RDONLY)) < 0 ){
		DERROR("NO [%s] file\n", path);
		return 'O';
	}

	/* 讀檔案的頭兩個位元組 */
	if ((ret = read(fd, picture, 2)) < 2){
		DERROR("read [%s] file error\n", path);
		close(fd);
		return 'R';
	}

	if((picture[0] != 0xff) || (picture[1] != 0xd8)){
		DERROR("It's not a JPG file\n");
		close(fd);
		return 'N';
	}

	lseek(fd, -2, SEEK_END);

	/* 讀檔案的最後兩個位元組 */
	if ((ret = read(fd, picture, 2)) < 2){
		DERROR("read [%s] file error\n", path);
		close(fd);
		return 'R';
	}

	if((picture[0] != 0xff) || (picture[1] != 0xd9)){
		DERROR("It's not a BMP file\n");
		close(fd);
		return 'N';
	}else{
		close(fd);
		return 'Y';
	}
}


/* 判斷是否為 png 檔案*/
static char im_is_png(const     char *path)
{
	unsigned char *buf = malloc(sizeof(8));
	unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
	int fd = -1;

	if ((fd = open(path, O_RDONLY)) < 0){
		DERROR("NO [%s] file\n", path);
		return 'O';
	}

	if (read(fd, buf, 8) != 8){
		DERROR("read [%s] file error\n", path);
		close(fd);
		return 'R';
	}

	/*判斷前 PNG_BYTES_TO_CHECK 個位元組是否是 (89 50 4E 47 0D 0A 1A 0A 16進位制) */
	if(memcmp(buf, png_signature, 8) != 0){ 
		DERROR("It's not a PNG file\n");
		close(fd);
		return 'N';
	}else{
		close(fd);
		return 'Y';
	}
}

 

讀取連結串列尾節點:

由於多檔案程式中,用指標做全域性變數會帶來一些問題,因此這裡用函式的形式來進行多檔案之間的溝通。

/* 讀取連結串列尾節點 */
iamge_file_node_s   *im_read_fail(void)
{
	return tail_file_node;
}

銷燬連結串列:

/* 銷燬連結串列 */
int im_manage_destroy(void)
{
	iamge_file_node_s *p_node_1 = NULL;
	iamge_file_node_s *p_node_2 = NULL;
	
	if(file_head.next == NULL){
		DEBUG("不用銷燬\n");
		return 0;
	}

	p_node_1 = file_head.next;
	p_node_2 = file_head.next->next;
	
	while(p_node_2 != NULL)
	{
		free(p_node_1);
		p_node_1 = p_node_2;
		p_node_2 = p_node_1->next;
	}

	free(p_node_1);

	p_node_1 = p_node_2 = file_head.next = NULL;

	return 0;
}