Learning notes: practical application of system IO (displaying bmp pictures)

catalogue

1, 24 bit bmp picture format features

2, Specific implementation ideas

Question 1:

Question 2:

1, 24 bit bmp picture format features

         54 header bytes, 3 bytes for each pixel, BGR order, upside down storage, if the number of bytes occupied by the width of bmp picture cannot be divided by 4, the window system will fill each line with garbage, enough to divide by 4 bytes.

         LCD: each pixel occupies 4 bytes, and the values of ARGB are listed respectively. A indicates transparency

         The 54 byte header information is described in detail in another big man's blog. The following is a link: 24 bit picture features

2, Specific implementation ideas

        Step 1: open the picture you want to display. It must be in bmp format.   open()

        Step 2: turn on the LCD driver of the development board.   open("/dev/fb0")

        Step 3: read the pixels of the picture and save them to buf. (after the value of the effective pixel is 54 bytes, use lseek() to move the cursor) read().

        Part IV: write pixels to the LCD, which must correspond, otherwise the picture will be distorted.

        Finally, turn off the image and LCD.

#include "myhead.h"

int main(int argc,char **argv)
{
	int i;
	int x,y;
	int bmpfd;
	int lcdfd;
	//Define the array to store the read color value
	char bmpbuf[800*480*3];  //BGR data
	//Define the array to store the ARGB data obtained by conversion
	int lcdbuf[800*480];
	//Define a temporary array
	int tempbuf[800*480];
	//Open the bmp picture to display
	bmpfd=open(argv[1],O_RDWR);
	if(bmpfd==-1)
	{
		perror("open bmp fail!\n");
		return -1;
	}
	
	//Turn on the LCD driver
	lcdfd=open("/dev/fb0",O_RDWR);
	if(lcdfd==-1)
	{
		perror("open lcd fail!\n");
		return -1;
	}
	
	//Skip 54 bytes of header information and read from 55
	lseek(bmpfd,54,SEEK_SET);
	
	//Read from 55 bytes
	read(bmpfd,bmpbuf,800*480*3);
	
	//Convert 3 bytes of bmp data -- "into 4 bytes of ARGB data
	/*
	bmpbuf[0]-->R
	bmpbuf[1]-->G
	bmpbuf[2]-->B
	*/
	for(i=0; i<800*480; i++) //Ensure that each pixel can be converted
		lcdbuf[i]=0x00<<24|bmpbuf[3*i+2]<<16|bmpbuf[3*i+1]<<8|bmpbuf[3*i];
		
	//(x,y) this point is exchanged with (x,479-y) lcdbuf[y*800+x]
	//Turn the picture upside down
	for(x=0; x<800; x++)
		for(y=0; y<480; y++)
			//lcdbuf[(479-y)*800+x]=lcdbuf[y*800+x]; // Error, you should not assign values to yourself
            tempbuf[(479-y)*800+x]=lcdbuf[y*800+x];
	//Fill the converted ARGB data into the LCD screen
	write(lcdfd,tempbuf,800*480*4);
	
	//close
	close(bmpfd);
	close(lcdfd);
	return 0;
}

Question 1:

         write() is too inefficient and slow to display images.

        reason:

          Solution: #include < sys / MMAN. H >
                   void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
                          Return value: the first address of the LCD screen is returned successfully
                                  Failed NULL
                            Parameter: addr -- "is generally set to NULL, indicating that the operating system automatically allocates the first address of the hardware
                                  length -- the address size of the LCD screen you want to map   800*480*4
                                  prot -- access permission of memory area
                                              PROT_READ    // readable
                                              PROT_WRITE   // Writable
                                  flags - "can your mapped address space be shared
                                              MAP_SHARED   Can share
                                              MAP_PRIVATE   Cannot share
                                  fd -- file descriptor of the hardware device you want to map
                                  Offset -- address offset, generally set to 0
                        Unmap
                            int munmap(void *addr, size_t length);
                            Parameter: addr -- "the first address you mapped before
                                  length -- mapped memory size  

        Question 2:

                How to display images of any size at any position

                

#include "myhead.h"

int showbmp(int x,int y,char *bmpname);

int main(int argc,char **argv)
{
	int x = atoi(argv[2]);//atoi() converts a character type to an integer
	int y = atoi(argv[3]);
	
	showbmp(x,y,argv[1]);
	return 0;
}

int showbmp(int x,int y,char *bmpname)
{
	int i,j,k=0;
	int w,h;//Width and height of the picture
	int bmpfd;
	int lcdfd;
	int headbuf[2]={0};//headbuf[0] width headbuf[1] height
	
	//Define the array to store the ARGB data obtained by conversion
	int lcdbuf[800*480];
	//Open the bmp picture to display
	bmpfd=open(bmpname,O_RDWR);
	if(bmpfd==-1)
	{
		perror("open bmp fail!\n");
		return -1;
	}
	//Turn on the LCD driver
	lcdfd=open("/dev/fb0",O_RDWR);
	if(lcdfd==-1)
	{
		perror("open lcd fail!\n");
		return -1;
	}
	
	//The first address of lcd is mapped
	int *lcdmem=mmap(NULL,800*480*4, PROT_READ |PROT_WRITE,MAP_SHARED ,lcdfd,0 );
	
	lseek(bmpfd,18,SEEK_SET);
	//Read header information
	read(bmpfd,headbuf,8);
	w=headbuf[0];
	h=headbuf[1];
	
	if(x+w>800||y+h>480 ) //Judge whether the image is within a reasonable range
	{
		perror("Picture out of range!\n");
		return -1;
	}
	//Define the array to store the read color value
	char bmpbuf[w*h*3];  //BGR data
	//Define a temporary array
	int tempbuf[w*h];

	//Skip 54 bytes of header information and read from 55
	lseek(bmpfd,28,SEEK_CUR);
	if((3*w)%4==0)
	{
		read(bmpfd,bmpbuf,w*h*3);	//Read from 55 bytes
	}else 
	{
		for(int k=0;k<h;k++)
		{
			read(bmpfd,&bmpbuf[k*w*3],w*3);
			lseek(bmpfd,4-(3*w)%4,SEEK_CUR );
		}
	}
	for(i=0; i<w*h; i++) //Ensure that each pixel can be converted
		lcdbuf[i]=0x00<<24|bmpbuf[3*i+2]<<16|bmpbuf[3*i+1]<<8|bmpbuf[3*i];
	
	//Turn the picture upside down
	for(i=0; i<w; i++)
		for(int j=0; j<h; j++)
            tempbuf[(h-j)*w+i]=lcdbuf[j*w+i];
	//Determine coordinates
	for(i=0;i<h;i++)
		for(int j=0;j<w;j++)
		{
			*(lcdmem+800*(i+y)+j+x)=tempbuf[k];
			k++;
		}
		
	//close
	close(bmpfd);
	close(lcdfd);
	//Unmap
	munmap(lcdmem,800*480*3);
	return 0;

}

Tags: Linux

Posted on Wed, 06 Oct 2021 14:58:16 -0400 by sysgenmedia