2024-04-26 03:53 AM
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.
Solved! Go to Solution.
2024-04-30 11:17 AM
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
2024-04-26 11:50 PM
chatgpt didn't solve much, better natural stupidity than artificial intelligence... :D
2024-04-27 03:23 PM
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.
2024-04-28 06:06 AM
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:
similar problems. Is there a decent solution?
Thanks Tesla DeLorean
2024-04-29 10:34 AM
Really strange, has anyone really had this problem? I'll post some pictures tomorrow.
2024-04-29 11:19 AM - edited 2024-04-29 11:39 AM
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
2024-04-30 01:02 AM
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.
Thanks.
2024-04-30 02:06 AM
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
2024-04-30 03:32 AM
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.
2024-04-30 03:54 AM
As requested by JTP I did some tests, I created test images measuring 580x1000, slightly smaller than the display, the images are 565 bitmaps:
the result is:
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..