Skip to main content
Msolinas
Senior
April 26, 2024
Solved

Portrait readBMP24File

  • April 26, 2024
  • 4 replies
  • 4371 views

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.

This topic has been closed for replies.
Best answer by JTP1

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] << 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);

 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

4 replies

Msolinas
MsolinasAuthor
Senior
April 27, 2024

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

 

Tesla DeLorean
Guru
April 27, 2024

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 VenmoUp vote any posts that you find helpful, it shows what's working..
Msolinas
MsolinasAuthor
Senior
April 28, 2024

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

Msolinas
MsolinasAuthor
Senior
April 29, 2024

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

JTP1Best answer
Graduate II
April 30, 2024

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] << 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);

 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

Msolinas
MsolinasAuthor
Senior
May 1, 2024

IT WORKS!

Msolinas_0-1714564886071.png

 

Thanks JTP, really thanks, everything works and does what it's supposed to.
However, I would like to reflect on what happened.
Basically I didn't want someone to do the job for me, I'm grateful to JTP for providing me with the solution, but I was looking for someone who had the problem and solved it with a supplement to the lack of touchgfx.
The intervention of MORADI ESFAHANIASL was superfluous, he explained how the water is heated, if he had read the problem from the beginning he would have realized that this was what I was saying from the first moment.
I don't deal with interfaces in general, I'm a consultant who usually works on power and control systems for motors and inverters, but here I had an interface and I started the project two years ago encouraged by ST's direct tool.
A tool that is not open source for half of its system, which helps you, but apparently not all the way.
Here, now, imagine having an enormous amount of work, having (like everyone) tight deadlines and having to rediscover everything starting from the wheel because a hole of this level is left open in the support, an algorithm is produced and provided for a horizontal but not vertical display...."you do it"... imagine telling that to a customer. I actually had a psychological refusal to want to watch it...
The tool is certainly free, but is this the type of support you have if you rely professionally on a brand?
You may not like it, but it's my opinion.
A huge thank you to JTP, if you send me your address as a private message, I will repay your time with a gift from Italy!

 

 

Graduate II
May 1, 2024

Hello

Glad you get your problem solved. For me, the motivation for trying to solve these problems is purely willingness to learn more and get better understanding about TGFX. So this lesson is also very useful for me in my future challenges.

I think it would be good idea to update the example of reading a bitmap from a file so that it has support also portrait mode.

Anycase @Mohammad MORADI ESFAHANIASL post about framebuffer organisation and also tip about portrait mode implementation in QR code widget were helpful. Maybe this kind information (clear pictures) could be even in framebuffer basic documentation in some format:

https://support.touchgfx.com/docs/basic-concepts/framebuffer

 

But actually, the the portrait mode of dynamic bitmaps is very well documented here, but who reads the documents... not me at least :face_with_tears_of_joy:

https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps

 

Maybe, in future releases, it would be useful to have better support for landscape and portrait views. For example so that any object on the screen could have separate location and rotation settings for different 'Orientation profiles', all image selections could have separate images for different orientations (buttons, images, sliders etc).

Happy Labor day for all.

Br JTP

 

 

 

 

Osman SOYKURT
Technical Moderator
May 6, 2024

Hello @Msolinas ,

We're sorry to hear that the support provided by our team did not fully meet your expectations. We thank @JTP1  for offering a helpful answer to your query.
From what I can see on this thread, @Mohammad MORADI ESFAHANIASLaimed to guide you toward finding a solution. However, I agree that our response times could have been more prompt. Like all the other TouchGFX supporters on the forum, we might be busy sometimes with other work, and that's the reason why we have a dedicated support team working on business cases.
So for the future, if you are working under tight deadlines as you mentioned, I invite you to contact us on these links, and be certain that your inquiries will be prioritized, and we will strive to deliver a high-quality response.

https://www.st.com/content/st_com/en/support/support-home.html

https://ols.st.com/s/

 

OsmanSOYKURT_0-1714985800062.png

 

Best regards,

Osman SOYKURTST Software Developer | TouchGFX