cancel
Showing results for 
Search instead for 
Did you mean: 

Portrait readBMP24File

Msolinas
Senior

My problems with Portrait orientation don't end.
I have a very large project where changing the architecture and function calls costs much more than changing a single function.

My problem is how?
The function is readBMP24File.
In my project it is loaded from several places and many different screens.
In the original project it works very well, many images are called or even of different sizes from an MMC with fatfs.
Has anyone solved the problem of changing orientation without having to change the position and orientation of the images?
I'm starting to have serious doubts that the touchgfx gui really helps in the work I do.
If anyone can help me in solving the problem with a new or different algorithm I would be grateful.

1 ACCEPTED SOLUTION

Accepted Solutions
JTP1
Lead

Hello

Please test the attached version. It should keep now the image same position in landscape and portrait mode (eg. rotates the image). was it what you needed ?

void BMPFileLoader::readBMP24File(Bitmap bitmap, FileHdl fileHandle)
{
    uint8_t data[50];
    seekFile(fileHandle, 0);
    readFile(fileHandle, data, 26); //read first part of header.

    const uint32_t offset = data[10] | (data[11] << 😎 | (data[12] << 16) | (data[12] << 24);
    const uint32_t width = data[18] | (data[19] << 😎 | (data[20] << 16) | (data[21] << 24);
    const uint32_t height = data[22] | (data[23] << 😎 | (data[24] << 16) | (data[25] << 24);

    readFile(fileHandle, data, offset - 26); //read rest of header.

    //get dynamic bitmap boundaries
    const uint32_t buffer_width = bitmap.getWidth();
    const uint32_t buffer_height = bitmap.getHeight();

    const uint32_t rowpadding = (4 - ((width * 3) % 4)) % 4;

    const Bitmap::BitmapFormat format = bitmap.getFormat();
    uint8_t* const  buffer8  = Bitmap::dynamicBitmapGetAddress(bitmap.getId());
    uint16_t* const buffer16 = (uint16_t*)buffer8;
	
	if(HAL::getInstance()->getDisplayOrientation() == ORIENTATION_LANDSCAPE) // original code for landscape
	{
		for (uint32_t y = 0; y < height; y++)
		{
			for (uint32_t x = 0; x < width; x++)
			{
				if (x % 10 == 0) //read data every 10 pixels = 30 bytes
				{
					if (x + 10 <= width) //read 10
					{
						readFile(fileHandle, data, 10 * 3); //10 pixels
					}
					else
					{
						readFile(fileHandle, data, (width - x) * 3 + rowpadding); //rest of line
					}
				}
				//insert pixel, if within dynamic bitmap boundaries
				if (x < buffer_width && ((height - y - 1) < buffer_height))
				{
					switch (format)
					{
					case Bitmap::RGB565:
						buffer16[x + (height - y - 1) * buffer_width] =
							LCD16bpp::getNativeColorFromRGB(data[(x % 10) * 3 + 2], data[(x % 10) * 3 + 1], data[(x % 10) * 3]);
						break;
					case Bitmap::RGB888:
						{
							//24 bit framebuffer
							const uint32_t inx = 3 * (x + (height - y - 1) * buffer_width);
							buffer8[inx + 0] = data[(x % 10) * 3 + 0];
							buffer8[inx + 1] = data[(x % 10) * 3 + 1];
							buffer8[inx + 2] = data[(x % 10) * 3 + 2];
							break;
						}
					case Bitmap::ARGB8888:
						{
							//24 bit framebuffer
							const uint32_t inx = 4 * (x + (height - y - 1) * buffer_width);
							buffer8[inx + 0] = data[(x % 10) * 3 + 0];
							buffer8[inx + 1] = data[(x % 10) * 3 + 1];
							buffer8[inx + 2] = data[(x % 10) * 3 + 2];
							buffer8[inx + 3] = 255; //solid
							break;
						}
					default:
						assert(!"Unsupported bitmap format in BMPFileLoader!");
					}
				}
			}
		}
	}
	else // portrait orientation
	{
		for (uint32_t y = 0; y < height; y++)
		{
			for (uint32_t x = 0; x < width; x++)
			{
				if (x % 10 == 0) //read data every 10 pixels = 30 bytes
				{
					if (x + 10 <= width) //read 10
					{
						readFile(fileHandle, data, 10 * 3); //10 pixels
					}
					else
					{
						readFile(fileHandle, data, (width - x) * 3 + rowpadding); //rest of line
					}
				}
				//insert pixel, if within dynamic bitmap boundaries. Manipulated for portrait mode.
				if ((buffer_width-x-1) < buffer_width && ((height - y - 1) < buffer_height))
				{
					switch (format)
					{
					case Bitmap::RGB565:
						buffer16[height-y-1 + ((buffer_width-x-1)  * buffer_height)] =
							LCD16bpp::getNativeColorFromRGB(data[(x % 10) * 3 + 2], data[(x % 10) * 3 + 1], data[(x % 10) * 3]);
					break;
					case Bitmap::RGB888:
						{
							//24 bit framebuffer
							const uint32_t inx = 3 * (height-y-1 + ((buffer_width-x-1)  * buffer_height));
							buffer8[inx + 0] = data[(x % 10) * 3 + 0];
							
							buffer8[inx + 1] = data[(x % 10) * 3 + 1];
							buffer8[inx + 2] = data[(x % 10) * 3 + 2];
							break;
						}
					case Bitmap::ARGB8888:
						{
							//24 bit framebuffer
							const uint32_t inx = 4 * (height-y-1 + ((buffer_width-x-1)  * buffer_height));
							buffer8[inx + 0] = data[(x % 10) * 3 + 0];
							buffer8[inx + 1] = data[(x % 10) * 3 + 1];
							buffer8[inx + 2] = data[(x % 10) * 3 + 2];
							buffer8[inx + 3] = 255; //solid
							break;
						}
					default:
						assert(!"Unsupported bitmap format in BMPFileLoader!");
					}
				}
			}
		}
	}	
}

Br JTP

View solution in original post

19 REPLIES 19
Msolinas
Senior

chatgpt didn't solve much, better natural stupidity than artificial intelligence... :D

 

Could you check the integrity of the files from the MMC vs those of the original files on a PC ? Say use a file read, and CRC method? Or put images in QSPI, etc.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you for your response and your intervention.

The project includes a USB MSC that allows me to see the fat on the MMC from the outside and upload and download the images, so yes, the images are not damaged, I can see them perfectly.
But the problem is still the same as a few posts ago.
This project works perfectly in landscape, I don't understand the reason for the malfunction in vertical. I had read on another post:

https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/dynamic-bitmap-display-in-vertical-screen/td-p/220403


similar problems. Is there a decent solution?
Thanks Tesla DeLorean

Really strange, has anyone really had this problem? I'll post some pictures tomorrow.

Hello again

Are you changing the orientation on the fly with code or permanently from TGX- designer for your project ?

With quick test, dynamic bitmaps are rotated and showed correctly when selecting portrait orientation from Designer. But certainly I didn't the test bitmap file loading because its not that simple to replicate, just some example which creates dynamic bitmap and fill it with some color pattern.

Can you show example (picture) what it looks like (wrong).

If you really need to rotate loaded image, It shouldn't be too difficult to rotate picture 90 degrees when loading it from file and drawing it to the dynamic bitmap.

Br JTP

Hi Br JTP, Thanks for the reply and I hope you can advise me in the right direction this time too.
Below in the photo, the settings on TGFX, the image that should be there and the one that comes out instead. There is a routine that loads shauffle images on the fly from a fat on MMC.
If the display is on lanscape no problem.
It is evident that it is the algorithm, even though the image is oriented in the right way. If I invert the coordinates obtained from: getBMP24Dimensions, I get a more recognizable but clearly incorrectly oriented image.

Msolinas_0-1714463947596.png

Msolinas_1-1714464041322.png

Msolinas_2-1714464069340.png

Msolinas_3-1714464088474.png

Thanks.

 

 

 

Looks interesting, especially your last trial. What if you use smaller picture which is not overlapping the screen (maybe some picture with clear lines, color bars etc) and make sure bmp file resolution is also smaller than display resolution. 

Can you also share your bitmap read function and also which color depth your display is using.

Br jtp

Hello @Msolinas ,

I have seen such issues with your images when there is a mismatch between the framebuffer format and the algorithm used for placing data inside the framebuffer. 
As @JTP1 mentioned, it would be helpful if you can share a small project that demonstrates this issue, or at least the code for your getBMP24Dimensions and bitmap read functions.

Mohammad MORADI
ST Software Developer | TouchGFX

As requested by JTP I did some tests, I created test images measuring 580x1000, slightly smaller than the display, the images are 565 bitmaps:

Msolinas_0-1714473853377.png

 

Msolinas_1-1714473873845.png

Msolinas_2-1714473895466.png

 

the result is:

Msolinas_3-1714474091047.png

 

Msolinas_4-1714474104830.png

Msolinas_6-1714474146691.png

it is clear that the image is reversed by the effect caused on the first one.
The next image is dismantled, perhaps due to an overlap on the cache, but I would focus on one of the problems at a time. As is evident, the algorithm is not in line with memory.

As for the algorithms, I simply used the one present in the touchgfx help:

 

void BMPFileLoader::readBMP24File(Bitmap bitmap,FileHdl fileHandle){

    uint8_t data[50];
    seekFile(fileHandle,0);
    readFile(fileHandle,data,26);

    const uint32_t offset=data[10]|(data[11]<<8)|(data[12]<<16)|(data[12]<<24);
    const uint32_t width=data[18]|(data[19]<<8)|(data[20]<<16)|(data[21]<<24);
    const uint32_t height=data[22]|(data[23]<<8)|(data[24]<<16)|(data[25]<<24);

    //could check offset here
    readFile(fileHandle,data,offset-26);//read rest of header.

    const uint32_t buffer_width=bitmap.getWidth();
    const uint32_t buffer_height=bitmap.getHeight();

    const uint32_t rowpadding=(4-((width*3)%4))%4;

    const Bitmap::BitmapFormat format=bitmap.getFormat();

    uint8_t* const  buffer8 =Bitmap::dynamicBitmapGetAddress(bitmap.getId());
    uint16_t* const buffer16=(uint16_t*)buffer8;

    for(uint32_t y=0;y<height;y++){

        for(uint32_t x=0;x<width;x++){

            if(x%10==0){

                if(x+10<=width){

                    readFile(fileHandle,data,10*3);

                }else{
                    readFile(fileHandle,data,(width-x)*3+rowpadding);
                }//
            }//

            if(x<buffer_width && ((height-y-1)<buffer_height)){

                switch (format){

                case Bitmap::RGB565:

                    buffer16[x+(height-y-1)*buffer_width]=
                    		LCD16bpp::getNativeColorFromRGB(data[(x%10)*3+2],data[(x%10)*3+1],data[(x%10)*3]);
                    break;

                case Bitmap::RGB888:
                	{

                        const uint32_t inx=3*(x+(height-y-1)*buffer_width);
                        buffer8[inx+0]=data[(x%10)*3+0];
                        buffer8[inx+1]=data[(x%10)*3+1];
                        buffer8[inx+2]=data[(x%10)*3+2];
                        break;
                    }//

                case Bitmap::ARGB8888:
                    {

                        const uint32_t inx=4*(x+(height-y-1)*buffer_width);
                        buffer8[inx+0]=data[(x%10)*3+0];
                        buffer8[inx+1]=data[(x%10)*3+1];
                        buffer8[inx+2]=data[(x%10)*3+2];
                        buffer8[inx+3]=255;
                        break;
                    }//

                default:
                    assert(!"Unsupported bitmap format in BMPFileLoader!");

                }//
            }//
        }//
    }//
}
//

Recalled, for example in the case of the first:

void RunScreenView::functionStepBMPLoadFirst(void){

	FIL fi;
	FRESULT fresult;

	fresult=f_stat(SysGetPathCombine(fl.resourcesDiskPath,fl.res[0].name),&eMMCHfno);
	//SE IL FILE ESISTE
	if(fresult==FR_OK){
		//COMBINO IL NOME CON LA PATH E LO APRO
		fresult=f_open(&fi,SysGetPathCombine(fl.resourcesDiskPath,fl.res[0].name),FA_READ);
		//SE VA TUTTO BENE
		if(fresult==FR_OK){

			uint16_t width;
			uint16_t height;
			//CONTROLLA CHE IL FILE SIA UTILIZZABILE DALL'ALGORITMO
			BMPFileLoader::getBMP24Dimensions(&fi,width,height);
			sbmpId[0]=Bitmap::dynamicBitmapCreate(width,height,Bitmap::RGB565);
			BMPFileLoader::readBMP24File(Bitmap(sbmpId[0]),&fi);
			simage[0].setBitmap(Bitmap(sbmpId[0]));
			simage[0].setXY(0U,DOW_BAR_Y_COORDINATE);
			//LA METTO NON VISIBILE
			simage[0].setVisible(false);
			//FONDAMENTALE CHE CHIUDA IL FILE
			f_close(&fi);
		}//
	}
}
//

 

Thanks for help..