FatFS文件系统相册图片显示小技巧

       此文针对对文件系统有一定了解的朋友。可能对需要实现图片保存至SD卡,带显示及删除功能有些帮助。为什么说小技巧,这里有个前提,暂时卖个关子。

       我们知道,保存图片,需要为图片命名。但怎么样做到保存的图片其命名唯一不重复呢?我所知道的两个简单的方法,一是,按时间命名,我们资源里面有时钟芯片,或者芯片具有RTC功能;二是,带数字方法,使用数字累加命名;第一种方法应该比较常见,简单,好操作。但时间错乱(为什么会错乱,很多原因,不列出来了)可能会导致重复的时间覆盖之前的图片,当然正常情况下不会出现,所以比较常用。咱们具体说说第二种,在没有时间作为命名的方式下,怎么做,这就是前面提到的前提。

       用第二种方法有什么弊端呢,这里列举一下,1.新增图片命名之前必须扫描之前已有的图片数量找到未使用的最大数(假设数据都是连续的,当然这不可能,除非没有删除操作);2.假如中间删除了一张或多张照片得填补空缺(解决办法,删除一张图片后,重新排序命名所有图片,但不可行,图片数量多了太费时);3.在第二条里面假如删除之后不排序那么新增的图片插入到其中(至于怎么插入其中,可能是获取文件名对比相邻两个文件名的数据是否连续),但查看图片时不会立马显示刚增加的图片;4.或许我们会想到,删除之后就不用该序号数,只管增加图片时数据累加即可,但从长远看不合适;

       这里叙述本人处理方法并附上相应代码片段:

      1.启动初始化时必须扫描SD卡当前图片总数,并保存下来

//这段代码在主函数各个资源初始化后执行
if(f_mount(fs,"0:",1) == FR_OK){
		sd_ok = 1;          //SD卡成功初始化标志(全局变量)
		Get_Pic_Nums();
}

//获取图片总数
void Get_Pic_Nums(void)
{
    FRESULT res;   
    FILINFO finfo;  
    DIR dir;	   
    TCHAR *fn;	
	res = f_opendir(&dir,"0:/PHOTO");  
	if(res == FR_OK)	
		{
			while (f_readdir(&dir, &finfo) == FR_OK){
				fn = finfo.fname;
				if(!fn[0])break;
				fileCnt++; //图片总数(全局变量)
			}
		}
	f_closedir(&dir);
}

2.保存图片获取文件名函数

//bmp组合成形如"0:PHOTO/PIC13141.bmp"的文件名
void camera_new_pathname(u8 *pname)
{	 
  u8 res;					 
  u16 index=1;
  u16 index_num;
  FILINFO finfo;  
  DIR dir;	   
  TCHAR *fn;	
  res = f_opendir(&dir,"0:/PHOTO");
  while (f_readdir(&dir, &finfo) == FR_OK){
	fn = finfo.fname;
	if(!fn[0]){
		f_closedir(&dir);
		break;
	}
	else{
		index_num = (fn[3]-0x30)*10000+(fn[4]-0x30)*1000+(fn[5]-0x30)*100+
        (fn[6]-0x30)*10+(fn[7]-0x30);
		//对比文件名编号是否一致,不一致则可以使用该文件名
		if(index != index_num){
			f_closedir(&dir);
			break;
		}
		else{
			index++;
		}
	}
 }
  sprintf((char*)pname,"0:PHOTO/PIC%05d.bmp",index);	
} 

3.获取相邻的两个文件名,在查看图片的过程中,会出现删除操作,删除之后需要显示当前删除的图片的下一张或上一张

//mode 0:只要当前文件名 1:前一个文件名和当前文件名 2:后一个文件名和当前文件名
u8 Get_File_Name(u8 name1[],u8 name2[],u16 index,u8 mode)
{
	u16 num = 0;
	FRESULT res;   
    FILINFO finfo;  
    DIR dir;	   
    TCHAR *fn;	
		res = f_opendir(&dir,"0:/PHOTO");  
		if(res == FR_OK)	
		{
			while (f_readdir(&dir, &finfo) == FR_OK){
				fn = finfo.fname;
				if(!fn[0]){
					f_closedir(&dir);
					return 0;
				}
				num++;
				if(mode == 0){
					if(num == index){
						strcpy(name1,"0:PHOTO/");
						strcat(name1,fn);
						f_closedir(&dir);
						return 1;
					}
				}
				else if(mode == 1){
					if(num == index-1){
						strcpy(name1,"0:PHOTO/");
						strcat(name1,fn);
					}
				else if(num == index){
						strcpy(name2,"0:PHOTO/");
						strcat(name2,fn);
						f_closedir(&dir);
						return 1;
					}
				}
				else if(mode == 2){
						if(num == index){
						strcpy(name1,"0:PHOTO/");
						strcat(name1,fn);	
					}
				else if(num == index+1){
						strcpy(name2,"0:PHOTO/");
						strcat(name2,fn);
						f_closedir(&dir);
						return 1;
					}
				}
			}
		}
	return 0;
}

4.显示图片函数

u8 show_picture(u16 index_num)
{
	  u8 pname[30];
	  u8 pname2[30];
		u8 state = 0;
		state = Get_File_Name(pname,pname2,index_num,0);
		if(state != 0){
			Show_Pic(pname);//通过文件名找到SD卡图片位置显示图片
			return 1;
		}
		else{
			return 0;
		}
}

5.删除图片函数

u8 delete_picture(u16 index_num)
{
	u16 num = 0;  	
	u8 pname[30];
	u8 pname2[30];
	u16 pic_nums = fileCnt;
	if(pic_nums == 0 || pic_nums < index_num){
		return 0;
	}
	if(pic_nums == index_num){
		Get_File_Name(pname,pname2,index_num,1);
		Show_Pic(pname);//通过文件名找到SD卡图片位置显示图片 
		f_unlink((const TCHAR*)pname2);
		fileCnt--;
		if(pic_nums == 1){
			return 0;
		}
		else{
			return 1;
		}
	}
	else{
		Get_File_Name(pname,pname2,index_num,2);
		Show_Pic(pname);//通过文件名找到SD卡图片位置显示图片
		f_unlink((const TCHAR*)pname);
		fileCnt--;
		return 2;
	}
}

6.保存图片函数

void save_picture(u8 sd_state)
{
	u8 pname[30];
	u8 res;	
	if(sd_state){//SD正常			
			camera_new_pathname(pname);
			res=Take_Pic(pname)//图片拍摄函数
			if(res){// 
			}
			else { 
				fileCnt++;
			} 
		}
	else{//无SD卡
		NO_SD_CARD();
	}	
}

7.图片查看循环函数

void check_pictures(u8 sd_state)
{
	//显示编号最大的图片先,尽量保证最近拍的最先显示
	u16 index = fileCnt;
	u8 state = 0;
	u8 flag = 1;
	if(sd_state == 0){//无SD卡
		NO_SD_CARD();
	}
	if(fileCnt == 0){//无图片
		NO_PICTURE();
	}
	if(flag == 1){
		state = show_picture(index);
	}
	while(flag){
		switch(按键序号){
				case 按键1:
					index --;
					state = show_picture(index);
					if(state == 0){
						index ++;
					}
				break;
				case 按键2:
					index ++;
					state = show_picture(index);
					if(state == 0){
						index --;
					}
				break;
				case 按键3:
					state = delete_picture(index);
					if(state == 0){//无照片
						NO_PICTURE();
					}
					else if(state == 1){//删除的是序号最高的图片,当前图片序号减一
						index--;
					}
					else{
						//删除的图片序号不是最高,无需操作
					}
				break;
				case 按键4:
					flag = 0;
				break;
			}
		}	
}

最终实测,千张级别的图片数量,操作速度可以保证,存在一个弊端无法解决,当在中间删除图片时,再次保存的图片会插入到其中,再次浏览图片图的时候,无法保证这些最近保存的图片最先显示。可能有牛人遇到类似的问题,有更好的答案,希望可以一起讨论。这本人的解决方法,没有完美的方法,只有更好的方法,期待大家的补充。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值