425 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************************************************************************
 | |
| * | File      	:   GUI_BMPfile.c
 | |
| * | Author      :   Waveshare team
 | |
| * | Function    :   Hardware underlying interface
 | |
| * | Info        :
 | |
| *                Used to shield the underlying layers of each master
 | |
| *                and enhance portability
 | |
| *----------------
 | |
| * |	This version:   V2.0
 | |
| * | Date        :   2018-11-12
 | |
| * | Info        :
 | |
| * 1.Change file name: GUI_BMP.c -> GUI_BMPfile.c
 | |
| * 2.fix: GUI_ReadBmp()
 | |
| *   Now Xstart and Xstart can control the position of the picture normally,
 | |
| *   and support the display of images of any size. If it is larger than
 | |
| *   the actual display range, it will not be displayed.
 | |
| #
 | |
| # Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| # of this software and associated documnetation files (the "Software"), to deal
 | |
| # in the Software without restriction, including without limitation the rights
 | |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| # copies of the Software, and to permit persons to  whom the Software is
 | |
| # furished to do so, subject to the following conditions:
 | |
| #
 | |
| # The above copyright notice and this permission notice shall be included in
 | |
| # all copies or substantial portions of the Software.
 | |
| #
 | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| # FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| # LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
| # THE SOFTWARE.
 | |
| #
 | |
| ******************************************************************************/
 | |
| 
 | |
| #include "GUI_BMPfile.h"
 | |
| #include "GUI_Paint.h"
 | |
| #include "../Config/Debug.h"
 | |
| 
 | |
| #include <fcntl.h>
 | |
| #include <unistd.h>
 | |
| #include <stdint.h>
 | |
| #include <stdlib.h>//exit()
 | |
| #include <string.h>//memset()
 | |
| #include <math.h>//memset()
 | |
| #include <stdio.h>
 | |
| 
 | |
| 
 | |
| //global variables related to BMP picture display
 | |
| UBYTE *bmp_dst_buf = NULL;
 | |
| UBYTE *bmp_src_buf = NULL;
 | |
| UDOUBLE bmp_width, bmp_height;
 | |
| UBYTE  bmp_BitCount;
 | |
| UDOUBLE bytesPerLine;
 | |
| UDOUBLE imageSize;
 | |
| UDOUBLE skip;
 | |
| BMPRGBQUAD  palette[256];
 | |
| extern UBYTE isColor;
 | |
| 
 | |
| static void Bitmap_format_Matrix(UBYTE *dst,UBYTE *src)
 | |
| {
 | |
| 	UDOUBLE i,j,k;
 | |
|     UBYTE *psrc = src;
 | |
|     UBYTE *pdst = dst;
 | |
|     UBYTE *p = psrc;
 | |
| 	UBYTE temp;
 | |
| 	UDOUBLE count;
 | |
| 	
 | |
| 	//Since the bmp storage is from the back to the front, it needs to be converted in reverse order.
 | |
| 	switch(bmp_BitCount)
 | |
| 	{
 | |
| 		case 1:
 | |
| 			pdst += (bmp_width * bmp_height);
 | |
| 			
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				pdst -= bmp_width;
 | |
| 				count = 0;
 | |
| 				for (j=0;j<(bmp_width+7)/8;j++)
 | |
| 				{
 | |
| 					temp = p[j];
 | |
| 					
 | |
| 					for (k=0;k<8;k++)
 | |
| 					{
 | |
| 						pdst[0]= ((temp & (0x80>>k)) >> (7-k));
 | |
| 						count++;
 | |
| 						pdst++;
 | |
| 						if (count == bmp_width)
 | |
| 						{
 | |
| 							break;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				pdst -= bmp_width;
 | |
| 				p += bytesPerLine;
 | |
| 			}
 | |
| 		break;
 | |
| 		case 4:
 | |
| 			pdst += (bmp_width * bmp_height);
 | |
| 
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				pdst -= bmp_width;
 | |
| 				count = 0;
 | |
| 				for (j=0;j<(bmp_width+1)/2;j++)
 | |
| 				{
 | |
| 					temp = p[j];
 | |
| 					pdst[0]= ((temp & 0xf0) >> 4);
 | |
| 					count++;
 | |
| 					pdst++;
 | |
| 					if (count == bmp_width)
 | |
| 					{
 | |
| 						break;
 | |
| 					}
 | |
| 
 | |
| 					pdst[0] = temp & 0x0f;
 | |
| 					count++;
 | |
| 					pdst++;
 | |
| 					if (count == bmp_width)
 | |
| 					{
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 				pdst -= bmp_width;
 | |
| 				p += bytesPerLine;
 | |
| 			}
 | |
| 		break;
 | |
| 		case 8:
 | |
| 			pdst += (bmp_width*bmp_height);
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				p = psrc+(i+1)*bytesPerLine;
 | |
| 				p -= skip;
 | |
| 				for(j=0;j<bmp_width;j++)
 | |
| 				{
 | |
| 					pdst -= 1;
 | |
| 					p -= 1;
 | |
| 					pdst[0] = p[0];
 | |
| 				}
 | |
| 			}
 | |
| 		break;
 | |
| 		case 16:
 | |
| 			pdst += (bmp_width*bmp_height*2);
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				p = psrc+(i+1)*bytesPerLine;
 | |
| 				p -= skip;
 | |
| 				for(j=0;j<bmp_width;j++)
 | |
| 				{
 | |
| 					pdst -= 2;
 | |
| 					p -= 2;
 | |
| 					pdst[0] = p[1];
 | |
| 					pdst[1] = p[0];
 | |
| 				}
 | |
| 			}
 | |
| 		break;
 | |
| 		case 24:
 | |
| 			pdst += (bmp_width*bmp_height*3);
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				p = psrc+(i+1)*bytesPerLine;
 | |
| 				p -= skip;
 | |
| 				for(j=0;j<bmp_width;j++)
 | |
| 				{
 | |
| 					pdst -= 3;
 | |
| 					p -= 3;
 | |
| 					pdst[0] = p[2];
 | |
| 					pdst[1] = p[1];
 | |
| 					pdst[2] = p[0];
 | |
| 				}
 | |
| 			}
 | |
| 		break;
 | |
| 		case 32:
 | |
| 			pdst += (bmp_width*bmp_height*4);
 | |
| 			for(i=0;i<bmp_height;i++)
 | |
| 			{
 | |
| 				p = psrc+(i+1)*bmp_width*4;
 | |
| 				for(j=0;j<bmp_width;j++)
 | |
| 				{
 | |
| 					pdst -= 4;
 | |
| 					p -= 4;
 | |
| 					pdst[0] = p[2];
 | |
| 					pdst[1] = p[1];
 | |
| 					pdst[2] = p[0];
 | |
| 					pdst[3] = p[3];
 | |
| 				}
 | |
| 			}
 | |
| 		break;
 | |
| 		
 | |
| 		default:
 | |
| 		break;
 | |
| 	}	
 | |
| }
 | |
| 
 | |
| static void DrawMatrix(UWORD Xpos, UWORD Ypos,UWORD Width, UWORD High,const UBYTE* Matrix)
 | |
| {
 | |
| 	UWORD i,j,x,y;
 | |
| 	UBYTE R,G,B;
 | |
| 	UBYTE temp1,temp2;
 | |
| 	double Gray;
 | |
| 	
 | |
| 	for (y=0,j=Ypos;y<High;y++,j++)
 | |
| 	{
 | |
|  		for (x=0,i=Xpos;x<Width;x++,i++)
 | |
| 		{
 | |
| 			switch(bmp_BitCount)
 | |
| 			{
 | |
| 				case 1:
 | |
| 				case 4:
 | |
| 				case 8:
 | |
| 					R = palette[Matrix[(y*Width+x)]].rgbRed;
 | |
| 					G = palette[Matrix[(y*Width+x)]].rgbGreen;
 | |
| 					B = palette[Matrix[(y*Width+x)]].rgbBlue;
 | |
| 				break;
 | |
| 				
 | |
| 				case 16:
 | |
| 					temp1 = Matrix[(y*Width+x)*2];
 | |
| 					temp2 = Matrix[(y*Width+x)*2+1];
 | |
| 					R = (temp1 & 0x7c)<<1;
 | |
| 					G = (((temp1 & 0x03) << 3 ) | ((temp2&0xe0) >> 5))<<3;
 | |
| 					B = (temp2 & 0x1f)<<3;
 | |
| 				break;
 | |
| 				
 | |
| 				case 24:
 | |
| 					R = Matrix[(y*Width+x)*3];
 | |
| 					G = Matrix[(y*Width+x)*3+1];
 | |
| 					B = Matrix[(y*Width+x)*3+2];
 | |
| 				break;
 | |
| 				
 | |
| 				case 32:
 | |
| 					R = Matrix[(y*Width+x)*4];
 | |
| 					G = Matrix[(y*Width+x)*4+1];
 | |
| 					B = Matrix[(y*Width+x)*4+2];
 | |
| 				break;
 | |
| 				
 | |
| 				default:
 | |
| 				break;
 | |
| 			}
 | |
| 		
 | |
| 			Gray = (R*299 + G*587 + B*114 + 500) / 1000;
 | |
|             if(isColor && i%3==2)
 | |
| 				Paint_SetPixel(i, j, Gray/2);
 | |
| 			else
 | |
| 				Paint_SetPixel(i, j, Gray);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| UBYTE GUI_ReadBmp(const char *path, UWORD x, UWORD y)
 | |
| {
 | |
| 	//bmp file pointer
 | |
| 	FILE *fp;
 | |
| 	BMPFILEHEADER FileHead;
 | |
| 	BMPINFOHEADER InfoHead;
 | |
| 	UDOUBLE total_length;
 | |
| 	UBYTE *buf = NULL;
 | |
| 	UDOUBLE ret = -1;
 | |
| 	
 | |
| 	fp = fopen(path,"rb");
 | |
| 	if (fp == NULL)
 | |
| 	{
 | |
| 		return(-1);
 | |
| 	}
 | |
|  
 | |
| 	ret = fread(&FileHead, sizeof(BMPFILEHEADER),1, fp);
 | |
| 	if (ret != 1)
 | |
| 	{
 | |
| 		Debug("Read header error!\n");
 | |
| 		fclose(fp);
 | |
| 		return(-2);
 | |
| 	}
 | |
| 
 | |
| 	//Detect if it is a bmp image, since BMP file type is "BM"(0x4D42)
 | |
| 	if (FileHead.bType != 0x4D42)
 | |
| 	{
 | |
| 		Debug("It's not a BMP file\n");
 | |
| 		fclose(fp);
 | |
| 		return(-3);
 | |
| 	}
 | |
| 	
 | |
| 	Debug("*****************************************\n");
 | |
| 	Debug("BMP_bSize:%d \n", FileHead.bSize);
 | |
|  	Debug("BMP_bOffset:%d \n", FileHead.bOffset);
 | |
| 	
 | |
| 	ret = fread((char *)&InfoHead, sizeof(BMPINFOHEADER),1, fp);
 | |
| 	if (ret != 1)
 | |
| 	{
 | |
| 		Debug("Read infoheader error!\n");
 | |
| 		fclose(fp);
 | |
| 		return(-4);
 | |
| 	}
 | |
| 	
 | |
| 	Debug("BMP_biInfoSize:%d \n", InfoHead.biInfoSize);
 | |
|  	Debug("BMP_biWidth:%d \n", InfoHead.biWidth);
 | |
| 	Debug("BMP_biHeight:%d \n", InfoHead.biHeight);
 | |
| 	Debug("BMP_biPlanes:%d \n", InfoHead.biPlanes);
 | |
| 	Debug("BMP_biBitCount:%d \n", InfoHead.biBitCount);
 | |
| 	Debug("BMP_biCompression:%d \n", InfoHead.biCompression);
 | |
| 	Debug("BMP_bimpImageSize:%d \n", InfoHead.bimpImageSize);
 | |
| 	Debug("BMP_biXPelsPerMeter:%d \n", InfoHead.biXPelsPerMeter);
 | |
| 	Debug("BMP_biYPelsPerMeter:%d \n", InfoHead.biYPelsPerMeter);
 | |
| 	Debug("BMP_biClrUsed:%d \n", InfoHead.biClrUsed);
 | |
| 	Debug("BMP_biClrImportant:%d \n", InfoHead.biClrImportant);
 | |
| 	
 | |
| 	total_length = FileHead.bSize-FileHead.bOffset;
 | |
| 	bytesPerLine=((InfoHead.biWidth*InfoHead.biBitCount+31)>>5)<<2;
 | |
| 	imageSize=bytesPerLine*InfoHead.biHeight;
 | |
| 	skip=(4-((InfoHead.biWidth*InfoHead.biBitCount)>>3))&3;
 | |
| 	
 | |
| 	Debug("bimpImageSize:%d\n", InfoHead.bimpImageSize);
 | |
| 	Debug("total_length:%d\n", total_length);
 | |
| 	Debug("bytesPerLine = %d\n", bytesPerLine);
 | |
| 	Debug("imageSize = %d\n", imageSize);
 | |
| 	Debug("skip = %d\n", skip);
 | |
| 	Debug("*****************************************\n");
 | |
| 	
 | |
|     bmp_width = InfoHead.biWidth;
 | |
|     bmp_height = InfoHead.biHeight;
 | |
| 	bmp_BitCount = InfoHead.biBitCount;
 | |
| 	
 | |
| 	//This is old code, but allocate imageSize byte memory is more reasonable
 | |
|     bmp_src_buf = (UBYTE*)calloc(1,total_length);
 | |
| 	//bmp_src_buf = (UBYTE*)calloc(1,imageSize);
 | |
|     if(bmp_src_buf == NULL){
 | |
|         Debug("Load > malloc bmp out of memory!\n");
 | |
|         return -1;
 | |
|     }
 | |
| 	//This is old code, but allocate imageSize byte memory is more reasonable
 | |
| 	bmp_dst_buf = (UBYTE*)calloc(1,total_length);
 | |
| 	//bmp_dst_buf = (UBYTE*)calloc(1,imageSize);
 | |
|     if(bmp_dst_buf == NULL){
 | |
|         Debug("Load > malloc bmp out of memory!\n");
 | |
|         return -2;
 | |
|     }
 | |
| 
 | |
| 	 //Jump to data area
 | |
|     fseek(fp, FileHead.bOffset, SEEK_SET);
 | |
| 	
 | |
| 	//Bytes per line
 | |
|     buf = bmp_src_buf;
 | |
|     while ((ret = fread(buf,1,total_length,fp)) >= 0) 
 | |
| 	{
 | |
|         if (ret == 0) 
 | |
| 		{
 | |
|             DEV_Delay_us(100);
 | |
|             continue;
 | |
|         }
 | |
| 		buf = ((UBYTE*)buf) + ret;
 | |
|         total_length = total_length - ret;
 | |
|         if(total_length == 0)
 | |
|             break;
 | |
|     }
 | |
| 	
 | |
| 	//Jump to color pattern board
 | |
| 	switch(bmp_BitCount)
 | |
| 	{	
 | |
| 		case 1:
 | |
| 			fseek(fp, 54, SEEK_SET);
 | |
| 			ret = fread(palette,1,4*2,fp);
 | |
| 			if (ret != 8) 
 | |
| 			{
 | |
| 				Debug("Error: fread != 8\n");
 | |
| 				return -5;
 | |
| 			}
 | |
| 
 | |
| 			//this is old code, will likely result in memory leak if use 1bp source bmp image
 | |
| 			 
 | |
| 			bmp_dst_buf = (UBYTE*)calloc(1,InfoHead.biWidth * InfoHead.biHeight);
 | |
| 			if(bmp_dst_buf == NULL)
 | |
| 			{
 | |
| 				Debug("Load > malloc bmp out of memory!\n");
 | |
| 				return -5;
 | |
| 			}
 | |
| 			
 | |
| 		break;
 | |
| 		
 | |
| 		case 4:
 | |
| 			fseek(fp, 54, SEEK_SET);
 | |
| 			ret = fread(palette,1,4*16,fp);
 | |
| 			if (ret != 64) 
 | |
| 			{
 | |
| 				Debug("Error: fread != 64\n");
 | |
| 				return -5;
 | |
| 			}
 | |
| 			//this is old code, will likely result in memory leak if use 4bp source bmp image
 | |
| 			
 | |
| 			bmp_dst_buf = (UBYTE*)calloc(1,InfoHead.biWidth * InfoHead.biHeight);
 | |
| 			if(bmp_dst_buf == NULL)
 | |
| 			{
 | |
| 				Debug("Load > malloc bmp out of memory!\n");
 | |
| 				return -5;
 | |
| 			}
 | |
| 			
 | |
| 		break;
 | |
| 		
 | |
| 		case 8:
 | |
| 			fseek(fp, 54, SEEK_SET);
 | |
| 
 | |
| 			ret = fread(palette,1,4*256,fp);
 | |
| 
 | |
| 			if (ret != 1024) 
 | |
| 			{
 | |
| 				Debug("Error: fread != 1024\n");
 | |
| 				return -5;
 | |
| 			}
 | |
| 		break;
 | |
| 		
 | |
| 		default:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	Bitmap_format_Matrix(bmp_dst_buf,bmp_src_buf);
 | |
| 	DrawMatrix(x, y,InfoHead.biWidth, InfoHead.biHeight, bmp_dst_buf);
 | |
| 
 | |
|     free(bmp_src_buf);
 | |
|     free(bmp_dst_buf);
 | |
| 
 | |
| 	bmp_src_buf = NULL;
 | |
| 	bmp_dst_buf = NULL;
 | |
| 
 | |
| 	fclose(fp);
 | |
| 	return(0);
 | |
| } |