STM32 - EMWIN GIF image display (24)

EMWI

foreword

GIF images are used for transmission across data networks. The GIF standard supports interlacing, transparency, application-defined data, animation, and raw text rendering. emWin will ignore unsupported data such as raw text or application-specific data. GIF files use the LZW (Lempel-Zif-Welch) file compression method to compress image data, which operates without data loss. The output image is exactly the same as the input image.

1. GIF file support

The graphics library first decodes the graphics information. When displaying GIF images, the decoding process will take a long time. If the GIF file is used in a callback function that is often called by the window manager, the decoding process can also take a considerable amount of time. Computational time can be reduced by using a storage device, the best way is to draw the image to the storage device first, in which case the decompression will be done only once. emWin's GIF decompression process requires approximately 16 kilobytes of dynamically allocated RAM for decompression, and the RAM used for decompression is released after the image is drawn.

2. GIF file API function

GUI_GIF_Draw() 绘制已加载到存储器的 GIF 文件的第一个图像。
GUI_GIF_DrawEx() 绘制无需加载到存储器的 GIF 文件的第一个图像。
GUI_GIF_DrawSub() 绘制已加载到存储器的 GIF 文件的给定子图像。
GUI_GIF_DrawSubEx() 绘制无需加载到存储器的 GIF 文件的给定子图像。
GUI_GIF_DrawSubScaled() 绘制已加载到存储器的带比例的 GIF 文件的给定子图像。
GUI_GIF_DrawSubScaledEx() 绘制无需加载到存储器的带比例的 GIF 文件的给定子图像。
GUI_GIF_GetComment() 返回已加载到存储器的 GIF 文件给定的注释。
GUI_GIF_GetCommentEx() 返回无需加载到存储器的 GIF 文件的给定注释
GUI_GIF_GetImageInfo() 返回已加载到存储器的 GIF 文件的相关信息。
GUI_GIF_GetImageInfoEx() 返回无需加载到存储器的 GIF 文件的相关信息。
GUI_GIF_GetInfo() 返回已加载到存储器的 GIF 文件的相关信息。
GUI_GIF_GetInfoEx() 返回无需加载到存储器的 GIF 文件的相关信息。
GUI_GIF_GetXSize() 返回加载到存储器的位图的 X 大小。
GUI_GIF_GetXSizeEx() 返回无需加载到存储器的位图的 X 大小。
GUI_GIF_GetYSize() 返回加载到存储器的位图的 Y 大小。
GUI_GIF_GetYSizeEx() 返回无需加载到存储器的位图的 Y 大小。

3. Experimental demonstration

#include "gifdisplay.h"
#include "EmWinHZFont.h"
#include "GUI.h"
#include "malloc.h"
#include "ff.h"
#include "lcd.h"


#if SYSTEM_SUPPORT_UCOS
#include "includes.h"					//ucos ʹÓÃ	  
#endif

static FIL GIFFile;
static char gifBuffer[GIFPERLINESIZE];
/*******************************************************************
*
*       Static functions
*
********************************************************************
*/
/*********************************************************************
*
*       GifGetData
*
* Function description
*   This routine is called by GUI_GIF_DrawEx(). The routine is responsible
*   for setting the data pointer to a valid data location with at least
*   one valid byte.
*
* Parameters:
*   p           - Pointer to application defined data.
*   NumBytesReq - Number of bytes requested.
*   ppData      - Pointer to data pointer. This pointer should be set to
*                 a valid location.
*   StartOfFile - If this flag is 1, the data pointer should be set to the
*                 beginning of the data stream.
*
* Return value:
*   Number of data bytes available.
*/
static int GifGetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off) 
{
    
    
	static int readaddress=0;
	FIL * phFile;
	UINT NumBytesRead;
	#if SYSTEM_SUPPORT_UCOS
		OS_CPU_SR cpu_sr;
	#endif
	
	phFile = (FIL *)p;
	
	if (NumBytesReq > sizeof(gifBuffer)) 
	{
    
    
		NumBytesReq = sizeof(gifBuffer);
	}

	//Òƶ¯Ö¸Õëµ½Ó¦¸Ã¶ÁÈ¡µÄλÖÃ
	if(Off == 1) readaddress = 0;
	else readaddress=Off;
	
	#if SYSTEM_SUPPORT_UCOS
		OS_ENTER_CRITICAL();	//ÁÙ½çÇø
	#endif
	f_lseek(phFile,readaddress); 
	
	//¶ÁÈ¡Êý¾Ýµ½»º³åÇøÖÐ
	f_read(phFile,gifBuffer,NumBytesReq,&NumBytesRead);
	
		
	#if SYSTEM_SUPPORT_UCOS
		OS_EXIT_CRITICAL();	//Í˳öÁÙ½çÇø
	#endif
	
	*ppData = (U8 *)gifBuffer;
	return NumBytesRead;//·µ»Ø¶ÁÈ¡µ½µÄ×Ö½ÚÊý
}

//ÔÚÖ¸¶¨Î»ÖÃÏÔʾ¼ÓÔص½RAMÖеÄGIFͼƬ
//GIFFileName:ͼƬÔÚSD¿¨»òÕßÆäËû´æ´¢É豸ÖеÄ·¾¶(ÐèÎļþϵͳ֧³Ö£¡)
//mode:ÏÔʾģʽ
//		0 ÔÚÖ¸¶¨Î»ÖÃÏÔʾ£¬ÓвÎÊýx,yÈ·¶¨ÏÔʾλÖÃ
//		1 ÔÚLCDÖмäÏÔʾͼƬ£¬µ±Ñ¡Ôñ´ËģʽµÄʱºò²ÎÊýx,yÎÞЧ¡£
//x:ͼƬ×óÉϽÇÔÚLCDÖеÄxÖáλÖÃ(µ±²ÎÊýmodeΪ1ʱ£¬´Ë²ÎÊýÎÞЧ)
//y:ͼƬ×óÉϽÇÔÚLCDÖеÄyÖáλÖÃ(µ±²ÎÊýmodeΪ1ʱ£¬´Ë²ÎÊýÎÞЧ)
//member:  Ëõ·Å±ÈÀýµÄ·Ö×ÓÏî
//denom:Ëõ·Å±ÈÀýµÄ·ÖĸÏî
//·µ»ØÖµ:0 ÏÔʾÕý³£,ÆäËû ʧ°Ü
int displaygif(char *GIFFileName,u8 mode,u32 x,u32 y,int member,int denom)
{
    
    
	int i;
	u16 bread;
	char *gifbuffer;
	char result;
	int XSize,YSize;
	GUI_GIF_INFO GifInfo;
	GUI_GIF_IMAGE_INFO ImageInfo;
	float Xflag,Yflag;
	
	#if SYSTEM_SUPPORT_UCOS
		OS_CPU_SR cpu_sr;
	#endif

	result = f_open(&GIFFile,(const TCHAR*)GIFFileName,FA_READ);	//´ò¿ªÎļþ
	//Îļþ´ò¿ª´íÎó»òÕßÎļþ´óÓÚJPEGMEMORYSIZE
	if((result != FR_OK) || (GIFFile.fsize>GIFMEMORYSIZE)) 	return 1;
	
	gifbuffer=mymalloc(SRAMEX,GIFFile.fsize);
	if(gifbuffer == NULL) return 2;
	
	#if SYSTEM_SUPPORT_UCOS
		OS_ENTER_CRITICAL();	//ÁÙ½çÇø
	#endif
		
	result = f_read(&GIFFile,gifbuffer,GIFFile.fsize,(UINT *)&bread); //¶ÁÈ¡Êý¾Ý
	if(result != FR_OK) return 3;
	
	#if SYSTEM_SUPPORT_UCOS
		OS_EXIT_CRITICAL();	//Í˳öÁÙ½çÇø
	#endif
	
	GUI_GIF_GetInfo(gifbuffer,GIFFile.fsize,&GifInfo);	//»ñÈ¡GIFͼƬÐÅÏ¢
	
	XSize = GifInfo.xSize;	//»ñÈ¡GIFͼƬµÄXÖá´óС
	YSize = GifInfo.ySize;	//»ñÈ¡GIFͼƬµÄYÖá´óС
	switch(mode)
	{
    
    
		case 0:	//ÔÚÖ¸¶¨Î»ÖÃÏÔʾͼƬ
			if((member == 1) && (denom == 1)) //ÎÞÐèËõ·Å£¬Ö±½Ó»æÖÆ
			{
    
    
				//ÔÚÖ¸¶¨Î»ÖÃÏÔʾJPEGͼƬ
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSub(gifbuffer,GIFFile.fsize,x,y,i);
					GUI_GIF_GetImageInfo(gifbuffer,GIFFile.fsize,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}else //·ñÔòͼƬÐèÒªËõ·Å
			{
    
    
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubScaled(gifbuffer,GIFFile.fsize,x,y,i,member,denom);
					GUI_GIF_GetImageInfo(gifbuffer,GIFFile.fsize,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}
			break;
		case 1:	//ÔÚLCDÖмäÏÔʾͼƬ
			if((member == 1) && (denom == 1)) //ÎÞÐèËõ·Å£¬Ö±½Ó»æÖÆ
			{
    
    
				//ÔÚLCDÖмäÏÔʾͼƬ
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSub(gifbuffer,GIFFile.fsize,(lcddev.width-XSize)/2-1,(lcddev.height-YSize)/2-1,i);
					GUI_GIF_GetImageInfo(gifbuffer,GIFFile.fsize,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}else //·ñÔòͼƬÐèÒªËõ·Å
			{
    
    
				Xflag = (float)XSize*((float)member/(float)denom);
				Yflag = (float)YSize*((float)member/(float)denom);
				XSize = (lcddev.width-(int)Xflag)/2-1;
				YSize = (lcddev.height-(int)Yflag)/2-1;
				
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubScaled(gifbuffer,GIFFile.fsize,XSize,YSize,i,member,denom);
					GUI_GIF_GetImageInfo(gifbuffer,GIFFile.fsize,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}
			break;
	}
	f_close(&GIFFile);		//¹Ø±ÕJPEGFileÎļþ
	myfree(SRAMEX,gifbuffer);	//ÊÍ·ÅÄÚ´æ
	return 0;
}

//ÔÚÖ¸¶¨Î»ÖÃÏÔʾÎÞÐè¼ÓÔص½RAMÖеÄGIFͼƬ(ÐèÎļþϵͳ֧³Ö£¡¶ÔÓÚСRAM£¬ÍƼöʹÓô˷½·¨£¡)
//GIFFileName:ͼƬÔÚSD¿¨»òÕßÆäËû´æ´¢É豸ÖеÄ·¾¶
//mode:ÏÔʾģʽ
//		0 ÔÚÖ¸¶¨Î»ÖÃÏÔʾ£¬ÓвÎÊýx,yÈ·¶¨ÏÔʾλÖÃ
//		1 ÔÚLCDÖмäÏÔʾͼƬ£¬µ±Ñ¡Ôñ´ËģʽµÄʱºò²ÎÊýx,yÎÞЧ¡£
//x:ͼƬ×óÉϽÇÔÚLCDÖеÄxÖáλÖÃ(µ±²ÎÊýmodeΪ1ʱ£¬´Ë²ÎÊýÎÞЧ)
//y:ͼƬ×óÉϽÇÔÚLCDÖеÄyÖáλÖÃ(µ±²ÎÊýmodeΪ1ʱ£¬´Ë²ÎÊýÎÞЧ)
//member:  Ëõ·Å±ÈÀýµÄ·Ö×ÓÏî
//denom:Ëõ·Å±ÈÀýµÄ·ÖĸÏî
//·µ»ØÖµ:0 ÏÔʾÕý³£,ÆäËû ʧ°Ü
int displaygifex(char *GIFFileName,u8 mode,u32 x,u32 y,int member,int denom)
{
    
    
	char result;
	int i;
	int XSize,YSize;
	float Xflag,Yflag;
	GUI_GIF_INFO GifInfo;
	GUI_GIF_IMAGE_INFO ImageInfo;

	result = f_open(&GIFFile,(const TCHAR*)GIFFileName,FA_READ);	//´ò¿ªÎļþ
	//Îļþ´ò¿ª´íÎó
	if(result != FR_OK) 	return 1;
		
	GUI_GIF_GetInfoEx(GifGetData,&GIFFile,&GifInfo);
	XSize = GifInfo.xSize;	//GIFͼƬX´óС
	YSize = GifInfo.ySize;	//GIFͼƬY´óС
	switch(mode)
	{
    
    
		case 0:	//ÔÚÖ¸¶¨Î»ÖÃÏÔʾͼƬ
			if((member == 1) && (denom == 1)) //ÎÞÐèËõ·Å£¬Ö±½Ó»æÖÆ
			{
    
    
				//ÔÚÖ¸¶¨Î»ÖÃÏÔʾBMPͼƬ
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubEx(GifGetData,&GIFFile,x,y,i);
					GUI_GIF_GetImageInfoEx(GifGetData,&GIFFile,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}else //·ñÔòͼƬÐèÒªËõ·Å
			{
    
    
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubScaledEx(GifGetData,&GIFFile,x,y,i,member,denom);
					GUI_GIF_GetImageInfoEx(GifGetData,&GIFFile,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}
			break;
		case 1:	//ÔÚLCDÖмäÏÔʾͼƬ
			if((member == 1) && (denom == 1)) //ÎÞÐèËõ·Å£¬Ö±½Ó»æÖÆ
			{
    
    
				//ÔÚLCDÖмäÏÔʾͼƬ
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubEx(GifGetData,&GIFFile,(lcddev.width-XSize)/2-1,(lcddev.height-YSize)/2-1,i);
					GUI_GIF_GetImageInfoEx(GifGetData,&GIFFile,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}else //·ñÔòͼƬÐèÒªËõ·Å
			{
    
    
				Xflag = (float)XSize*((float)member/(float)denom);
				Yflag = (float)YSize*((float)member/(float)denom);
				XSize = (lcddev.width-(int)Xflag)/2-1;
				YSize = (lcddev.height-(int)Yflag)/2-1;
				
				for(i=0;i<GifInfo.NumImages;i++)
				{
    
    
					GUI_GIF_DrawSubScaledEx(GifGetData,&GIFFile,XSize,YSize,i,member,denom);
					GUI_GIF_GetImageInfoEx(GifGetData,&GIFFile,&ImageInfo,i);
					GUI_Delay(ImageInfo.Delay ? ImageInfo.Delay*10:100);//ÑÓʱ
				}
			}
			break;
	}

	
	f_close(&GIFFile);		//¹Ø±ÕGIFFileÎļþ
	return 0;
}	

//GIFͼƬÏÔʾÀý³Ì
void gifdisplay_demo(void)
{
    
    
	
	GUI_SetBkColor(GUI_BLUE);
	GUI_SetFont(&GUI_FontHZ16);
	GUI_SetColor(GUI_RED);
	GUI_Clear();
	while(1)
	{
    
    
		//GUI_DispStringHCenterAt("ÔÚÖ¸¶¨Î»ÖÃÏÔʾһÕżÓÔص½RAMÖеÄGIFͼƬ",400,0);
		displaygif("0:/PICTURE/GIF/Áú.gif",1,20,20,2,1);
//		GUI_Delay(1000);
//		GUI_Clear();
//	
//		GUI_DispStringHCenterAt("ÔÚLCDÖмäÏÔʾһÕÅÀ©´ó2±¶µÄ¼ÓÔص½RAMÖеÄGIFͼƬ",400,0);
//		displaygif("0:/PICTURE/GIF/С»ÆÈË.gif",1,0,0,2,1);	
//		GUI_Delay(1000);
//		GUI_Clear();
//		
//		GUI_DispStringHCenterAt("ÔÚLCDÖмäÏÔʾһÕÅËõС1/2µÄ¼ÓÔص½RAMÖеÄGIFͼƬ",400,0);
//		displaygif("0:/PICTURE/GIF/»ð²ñÈË.gif",1,0,0,1,2);
//		GUI_Delay(1000);
//		GUI_Clear();
//		
//		GUI_DispStringHCenterAt("ÔÚÖ¸¶¨Î»ÖÃÏÔʾһÕÅÎÞÐè¼ÓÔصÄGIFͼƬ",400,0);
//		displaygifex("0:/PICTURE/GIF/Áú.gif",0,20,20,1,1);
//		GUI_Delay(1000);
//		GUI_Clear();
//		
//		GUI_DispStringHCenterAt("ÔÚLCDÖмäÏÔʾһÕÅÀ©´ó2±¶µÄÎÞÐè¼ÓÔصÄGIFͼƬ",400,0);
//		displaygifex("0:/PICTURE/GIF/С»ÆÈË.gif",1,0,0,2,1);	
//		GUI_Delay(1000);
//		GUI_Clear();
//	
//		GUI_DispStringHCenterAt("ÔÚLCDÖмäÏÔʾһÕÅËõС1/2µÄÎÞÐè¼ÓÔصÄGIFͼƬ",400,0);
//		displaygifex("0:/PICTURE/GIF/»ð²ñÈË.gif",1,0,0,1,2);
//		GUI_Delay(1000);
//		GUI_Clear();
	}
}

GifGetData () 从外部存储器获取 GIF 文件数据
displaygif ()将 GIF 图片加载到 RAM 中,并显示到 LCD 上,显示速度快,但是需要大量的 RAM。 
dispgifex() 不需要将 GIF 加载到 RAM 中,显示速度慢,但是不需要大量的 RAM。

The function GifGetData () is used to obtain the JPEG image data from the external memory, and is passed as a parameter to GUI_GIF_GetImageInfoEx () when the function displaygifex () displays the GIF image. The function displaygif () is used to display the GIF image. This function first loads all the data of the GIF image into the RAM, and then calls the corresponding function in EMWIN to display the GIF image loaded into the RAM on the LCD. Loaded into RAM, so requires a lot of RAM, but the display is fast! This function can set the position and magnification of the GIF image to be displayed. The function displaygifex () also displays GIF images. Different from the function displygif (), displaygifex () does not need to load GIF images into RAM, and can directly read GIF images from external memory and display them. This method requires The RAM is small, but the speed is slower than displygif (). This function can also set the position and magnification of the GIF image to be displayed.
insert image description here
insert image description here

Summarize

Like BMP and JPG, the front is a series of operations to read pictures, and finally display them. Just look at the code carefully.

Guess you like

Origin blog.csdn.net/qq_51963216/article/details/124088978