Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Qimage from tga with Alpha

Qimage from tga with Alpha

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 2 Posters 4.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • QT-static-prgmQ Offline
    QT-static-prgmQ Offline
    QT-static-prgm
    wrote on last edited by
    #1

    How can i open a tga file that contains an alpha channel?

    i need to open multiple tga files and i don't know whether it is tga 16, 24, 32 bits/pixel or RLE compressed.

    24 bits/pixel seams to work correctly, but the 32 bits/pixel (with alpha channel) do not work. Any solutions for that??

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      "do not work" is kinda vague, but I'm guessing you mean your images load as opaque, loosing alpha channel info or don't load at all.
      Qt tga plugin does not support RLE compression, but alpha channel should work just fine.
      Looking at which tga options you named I'm guessing you're using Photoshop (or other Adobe app) to save your images. Please note that Photoshop treats alpha in tga files kinda weird. It's not enough to save it in 32 bits. You need to actually go to layers panel, create a new alpha layer and fill it with the right alpha data, otherwise it will write the file with alpha channel all white (opaque).

      All in all tga is an old and poorly supported format (lots of weird gotchas in different apps). If possible consider switching to something else. For example png's are universally supported lossless format with alpha and metadata support.

      QT-static-prgmQ 1 Reply Last reply
      3
      • QT-static-prgmQ Offline
        QT-static-prgmQ Offline
        QT-static-prgm
        wrote on last edited by
        #3

        don't work in the meaning of load() returns NULL.

        I need the tga format, because the mesh files need them. You are right, I'm using PhotoShop elements 11 with some features from cs2 for layer support.

        Since I don't take care of the actually data stored in the alpha channel, it shouldn't matter how PhotoShop fills it. But I know PS good, so I know how to pass the data to alpha correctly. I'm not sure about the rle. I'll check that and tell you whether the file causing problems is rle compressed or not.

        1 Reply Last reply
        0
        • Chris KawaC Chris Kawa

          "do not work" is kinda vague, but I'm guessing you mean your images load as opaque, loosing alpha channel info or don't load at all.
          Qt tga plugin does not support RLE compression, but alpha channel should work just fine.
          Looking at which tga options you named I'm guessing you're using Photoshop (or other Adobe app) to save your images. Please note that Photoshop treats alpha in tga files kinda weird. It's not enough to save it in 32 bits. You need to actually go to layers panel, create a new alpha layer and fill it with the right alpha data, otherwise it will write the file with alpha channel all white (opaque).

          All in all tga is an old and poorly supported format (lots of weird gotchas in different apps). If possible consider switching to something else. For example png's are universally supported lossless format with alpha and metadata support.

          QT-static-prgmQ Offline
          QT-static-prgmQ Offline
          QT-static-prgm
          wrote on last edited by QT-static-prgm
          #4

          @Chris-Kawa i think you were right. I just opened the picture in PSE and restored it. Now it is working. So i guess it was rle compressed before

          Before i changed the project to Qt i used my own tga importer and stored the important information in a struct.
          Later i used glTexImage2D to add my texture.

          So would it be possible to use my code to support RLE, too?? My importer worked fine for 32 and 24 bit (16 did not for some reason) with and without RLE

          1 Reply Last reply
          0
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #5

            If you're using it with OpenGL then sure. You can use one of the QOpenGLTexture's setData overloads to transfer the data you get from your importer. You can also just use glTexImage2D directly and bypass Qt entirely. It's up to you.

            You can also write your own image plugin if you want to keep the convenient QImage interface.

            1 Reply Last reply
            1
            • QT-static-prgmQ Offline
              QT-static-prgmQ Offline
              QT-static-prgm
              wrote on last edited by
              #6

              all right. i think i'll stay with Qt for now and maybe add rle support later ;)

              first i need to fix this problem:
              Bild Text

              1 Reply Last reply
              0
              • Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by
                #7

                Is that a stormtrooper's helmet ? :) Looks like the vertices indexing is somehow messed up.

                1 Reply Last reply
                1
                • QT-static-prgmQ Offline
                  QT-static-prgmQ Offline
                  QT-static-prgm
                  wrote on last edited by
                  #8

                  imperial commando. it's used to look like that:

                  I think it's something about the index, too. But i don't understand what. Because things like this works:

                  ok, at the last one the rotating is wrong (no idea why)

                  1 Reply Last reply
                  0
                  • QT-static-prgmQ Offline
                    QT-static-prgmQ Offline
                    QT-static-prgm
                    wrote on last edited by QT-static-prgm
                    #9

                    @Chris-Kawa
                    I just added my own tga load function for those that are rle compressed. But it is not compressed. It's RGB 24 bit. Or can Qt not load tga with 24 bit??

                    ==EDIT==

                    Seams that qt can only open 32 bit images. But i have a different problem:

                    This needs to be solid green.

                    
                    		img = QImage(ui32Width, ui32Height, ui32BpP == 32? QImage::Format_ARGB32 : QImage::Format_RGB32);
                    		
                    		int pixelSize = ui32BpP == 32 ? 4 : 3;
                    
                    		for (unsigned int x = 0; x < ui32Width; x++)
                    		{
                    			for (unsigned int y = 0; y < ui32Height; y++)
                    			{
                    				int valr = vui8Pixels->at(x * ui32Width * pixelSize + y + 2);
                    				int valg = vui8Pixels->at(x * ui32Width * pixelSize + y + 1);
                    				int valb = vui8Pixels->at(x * ui32Width * pixelSize + y);
                    				int vala = vui8Pixels->at(x * ui32Width * pixelSize + y + 3);
                    
                    				QRgb value;
                    				if (ui32BpP == 32)
                    					value = qRgba(
                    						valr,
                    						valg,
                    						valb,
                    						vala
                    					);
                    				else
                    					value = qRgb(
                    						vui8Pixels->at(x * ui32Width * pixelSize + y),
                    						vui8Pixels->at(x * ui32Width * pixelSize + y + 1),
                    						vui8Pixels->at(x * ui32Width * pixelSize + y + 2)
                    					);
                    
                    				img.setPixel(x, y, value);
                    			}
                    		}
                    

                    vui8Pixel holds all pixel information (b,g,r,a,b,g,r,a,b,g,r,a,....)
                    i checked the valr, valg, valb,... values and they are correctly. So it need to be something with qRgba() or my QImage format. Any ideas??

                    1 Reply Last reply
                    0
                    • Chris KawaC Offline
                      Chris KawaC Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      I've checked and QImage reads 24bit images fine.
                      As for the problem - you seem to have your indexing wrong:

                      x * ui32Width * pixelSize + y + 2
                      

                      This should rather be

                      y * ui32Width * pixelSize + x + 2 //i.e. y * scanline + x
                      

                      Same for the other values.

                      Btw. This is very inefficient. First of all you should switch the loops like this:

                      for (unsigned int y = 0; y < ui32Height; y++) {
                         for (unsigned int x = 0; x < ui32Width; x++) {
                      

                      so that you look at the neighboring x values. This is much much more cache friendly.
                      Similarly, take a note at the docs - using setPixel is terribly inefficient. At each y iteration take a pointer to the scanline and use that instead (read the warning note in the docs).

                      1 Reply Last reply
                      1
                      • QT-static-prgmQ Offline
                        QT-static-prgmQ Offline
                        QT-static-prgm
                        wrote on last edited by
                        #11

                        oops, thanks. It works now.

                        The whole function is a bit more complicate

                        So how it works:
                        Try to open the image file using QImage. Since it is not very good for tga files, it sometimes does not work (in my case a 24 bit uncompressed does not worked, others do).
                        So if it cannot be loaded, i use my own old import function and if this function has problems, it just returns a solid red image.

                        Question:
                        is there a fast way to read from the file and write directly to the QImage?
                        The values are always unsigned int 8 bgr(a) if ui32BpP = 24 there is no alpha, if it is 32 there is an alpha value after bgr.

                        if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32))
                        {
                        	fsPicture.read(reinterpret_cast<char*>(vui8Pixels->data()), ui32Size);
                        }
                        

                        in the other case it is compressed and i need to do some more tricks to reconstruct the image. Here i'd calculate the image position with modulo and simply write directly on the QImage instead of the vector.

                        else if (ui32PicType == 10 && (ui32BpP == 24 || ui32BpP == 32))	// compressed
                        		{
                        			std::uint8_t tempChunkHeader;
                        			std::uint8_t tempData[5];
                        			unsigned int tempByteIndex = 0;
                        
                        			do {
                        				fsPicture.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
                        
                        				if (tempChunkHeader >> 7)	// repeat count
                        				{
                        					// just use the first 7 bits
                        					tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
                        
                        					fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
                        
                        					for (int i = 0; i <= tempChunkHeader; i++)
                        					{
                        						vui8Pixels->at(tempByteIndex++) = tempData[0];
                        						vui8Pixels->at(tempByteIndex++) = tempData[1];
                        						vui8Pixels->at(tempByteIndex++) = tempData[2];
                        						if (ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3];
                        					}
                        				}
                        				else						// data count
                        				{
                        					// just use the first 7 bits
                        					tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
                        
                        					for (int i = 0; i <= tempChunkHeader; i++)
                        					{
                        						fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
                        
                        						vui8Pixels->at(tempByteIndex++) = tempData[0];
                        						vui8Pixels->at(tempByteIndex++) = tempData[1];
                        						vui8Pixels->at(tempByteIndex++) = tempData[2];
                        						if (ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3];
                        					}
                        				}
                        			} while (tempByteIndex < ui32Size);
                        		}
                        

                        Here is the whole function

                        QImage loadTga(const char* filePath, bool &success)
                        {
                        	QImage img;
                        	if (!img.load(filePath))
                        	{
                        
                        		// open the file
                        		std::fstream fsPicture(filePath, std::ios::in | std::ios::binary);
                        
                        		if (!fsPicture.is_open())
                        		{
                        			img = QImage(1, 1, QImage::Format_RGB32);
                        			img.fill(Qt::red);
                        			success = false;
                        			return img;
                        		}
                        
                        		// some variables
                        		std::vector<std::uint8_t>* vui8Pixels;
                        		std::uint32_t ui32BpP;
                        		std::uint32_t ui32Width;
                        		std::uint32_t ui32Height;
                        
                        		// read in the header
                        		std::uint8_t ui8x18Header[19] = { 0 };
                        		fsPicture.read(reinterpret_cast<char*>(&ui8x18Header), sizeof(ui8x18Header) - 1);
                        
                        		//get variables
                        		vui8Pixels = new std::vector<std::uint8_t>;
                        		bool bCompressed;
                        		std::uint32_t ui32IDLength;
                        		std::uint32_t ui32PicType;
                        		std::uint32_t ui32PaletteLength;
                        		std::uint32_t ui32Size;
                        
                        		// extract all information from header
                        		ui32IDLength = ui8x18Header[0];
                        		ui32PicType = ui8x18Header[2];
                        		ui32PaletteLength = ui8x18Header[6] * 0x100 + ui8x18Header[5];
                        		ui32Width = ui8x18Header[13] * 0x100 + ui8x18Header[12];
                        		ui32Height = ui8x18Header[15] * 0x100 + ui8x18Header[14];
                        		ui32BpP = ui8x18Header[16];
                        
                        		// calculate some more information
                        		ui32Size = ui32Width * ui32Height * ui32BpP / 8;
                        		bCompressed = ui32PicType == 9 || ui32PicType == 10;
                        		vui8Pixels->resize(ui32Size);
                        
                        		// jump to the data block
                        		fsPicture.seekg(ui32IDLength + ui32PaletteLength, std::ios_base::cur);
                        
                        		if (ui32PicType == 2 && (ui32BpP == 24 || ui32BpP == 32))
                        		{
                        			fsPicture.read(reinterpret_cast<char*>(vui8Pixels->data()), ui32Size);
                        		}
                        		// else if compressed 24 or 32 bit
                        		else if (ui32PicType == 10 && (ui32BpP == 24 || ui32BpP == 32))	// compressed
                        		{
                        			std::uint8_t tempChunkHeader;
                        			std::uint8_t tempData[5];
                        			unsigned int tempByteIndex = 0;
                        
                        			do {
                        				fsPicture.read(reinterpret_cast<char*>(&tempChunkHeader), sizeof(tempChunkHeader));
                        
                        				if (tempChunkHeader >> 7)	// repeat count
                        				{
                        					// just use the first 7 bits
                        					tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
                        
                        					fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
                        
                        					for (int i = 0; i <= tempChunkHeader; i++)
                        					{
                        						vui8Pixels->at(tempByteIndex++) = tempData[0];
                        						vui8Pixels->at(tempByteIndex++) = tempData[1];
                        						vui8Pixels->at(tempByteIndex++) = tempData[2];
                        						if (ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3];
                        					}
                        				}
                        				else						// data count
                        				{
                        					// just use the first 7 bits
                        					tempChunkHeader = (uint8_t(tempChunkHeader << 1) >> 1);
                        
                        					for (int i = 0; i <= tempChunkHeader; i++)
                        					{
                        						fsPicture.read(reinterpret_cast<char*>(&tempData), ui32BpP / 8);
                        
                        						vui8Pixels->at(tempByteIndex++) = tempData[0];
                        						vui8Pixels->at(tempByteIndex++) = tempData[1];
                        						vui8Pixels->at(tempByteIndex++) = tempData[2];
                        						if (ui32BpP == 32) vui8Pixels->at(tempByteIndex++) = tempData[3];
                        					}
                        				}
                        			} while (tempByteIndex < ui32Size);
                        		}
                        		// not useable format
                        		else
                        		{
                        			fsPicture.close();
                        			img = QImage(1, 1, QImage::Format_RGB32);
                        			img.fill(Qt::red);
                        			success = false;
                        			return img;
                        		}
                        
                        		fsPicture.close();
                        
                        		img = QImage(ui32Width, ui32Height, QImage::Format_RGB888);
                        		
                        		int pixelSize = ui32BpP == 32 ? 4 : 3;
                        		//TODO: write direct into img
                        		for (unsigned int x = 0; x < ui32Width; x++)
                        		{
                        			for (unsigned int y = 0; y < ui32Height; y++)
                        			{
                        				int valr = vui8Pixels->at(y * ui32Width * pixelSize + x * pixelSize + 2);
                        				int valg = vui8Pixels->at(y * ui32Width * pixelSize + x * pixelSize + 1);
                        				int valb = vui8Pixels->at(y * ui32Width * pixelSize + x * pixelSize);
                        
                        				QColor value(valr, valg, valb);
                        				img.setPixelColor(x, y, value);
                        			}
                        		}
                        
                        		img = img.mirrored();
                        
                        	}
                        	success = true;
                        	return img;
                        }
                        
                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved