Convert RGBA buffer to ARGB

Started by
11 comments, last by Khatharr 10 years, 8 months ago
Hello smile.png

I'm using LodePNG to load and decrypt PNG but the library return a RGBA buffer.

For my interface rendering i need a ARGB buffer so i wonder how can i convert my rgba buffer to argb ?

here is my code so far :

	std::vector<unsigned char> image; //the raw pixels
	unsigned width, height;

	//decode
	unsigned error = lodepng::decode(image, width, height, fileName);

	//if there's an error, display it
	if (error)
	{
		WriteError("%s decoding error %u : %s", fileName, error, lodepng_error_text(error));
		return FALSE;
	}


	char* rgbaBuffer = reinterpret_cast<char*>(&image[0]);
Advertisement

Re-order the pixels components as needed.

The simplest solution would perhaps be this one, where the vector's content is re-ordered in-place by using the operator[] for accessing:


for(uint pos = 0; pos < image.size(); pos += 4) {
    unsigned char r = image[pos+0];
    unsigned char g = image[pos+1];
    unsigned char b = image[pos+2];
    unsigned char a = image[pos+3];
    image[pos+0] = a;
    image[pos+1] = r;
    image[pos+2] = g;
    image[pos+3] = b;
}

It relies on the image providing 4 components per pixel. You could use the more safe but less efficient vector::at routine instead of the vector::operator[], of course. You could do some index trickery or pointer casting trickery.

Oh, swapping pixels. such joy.

Slightly fancier version, with some trickery which possibly makes it up to 4x faster on some systems tongue.png


unsigned int* buf = &image[0];
unsigned int* end = buf + image.size()/4;
while(buf < end) {
    unsigned int pixel = *buf;
    *buf = ((pixel&0xffffff00)>>8) + ((pixel&0xff)<<24);
    buf++;
}

Edit: did the wrong conversion at first...

Thank you guys !

Not looked at "LodePNG", but if it is uses libpng, libpng already provides all the transformations I have ever needed, like where to put the alpha bits (or add some fixed value if the source image had no alpha channel), so I would hope LodePNG lets you provide them.

Not looked at "LodePNG", but if it is uses libpng, libpng already provides all the transformations I have ever needed, like where to put the alpha bits (or add some fixed value if the source image had no alpha channel), so I would hope LodePNG lets you provide them.

LodePNG only consists of a .hpp and a .cpp file and doesn't use libpng.

I'd also suggest using libpng. Otherwise, Olof is definitely on the right track. You don't want to vectorize this kind of thing.

Although, for the sake of being a bit more arcane...


uint32_t* pix = buf;
pix += image.size() / 4;
while(pix >= &buf) {
  *pix-- = (*pix >> 8) | (*pix << 24);
}
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Hm... and if you want it really fast, do SSE versions:

SSSE3 version (really dumb and fast):


__m128i shuffler;
void rgba_to_argb(const int* in, int* out)
{
	const __m128i pixel = _mm_load_si128((__m128i*)in);
	const __m128i tmp = _mm_shuffle_epi8(pixel, shuffler);
	_mm_store_si128((__m128i*)out, tmp);
}

Where:



shuffler = _mm_setr_epi8(0x01, 0x02, 0x03, 0x00, 
			0x05, 0x06, 0x07, 0x04, 
			0x09, 0x0a, 0x0b, 0x08, 
			0x0d, 0x0e, 0x0f, 0x0c);

Of course you can upgrade it to support batch processing and thus making it even more effective.

Adapting code for lower SSE versions means emulating _mm_shuffle_epi8 instruction (which is possible with little overhead).

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

This is also embarrassingly parallel, so we could do some concurrent looping, or use the GPU. A pixel shader could do it in no time.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This is also embarrassingly parallel, so we could do some concurrent looping, or use the GPU. A pixel shader could do it in no time.

Computationally, its a good fit, but going across the PCIe bus and back again would probably kill any performance wins unless the image is really huge. Its probably better to leave it in system memory and use SSE. Some of the newer hardware that supports compute applications in system memory would probably win, but those are few and far between now. (FYI, all but the most recent integrated graphics solutions out there today that share memory with the host need to redundantly copy the data into the GPU's carved off portion of memory, because the CPU and GPU have independent address spaces. Even now, if you have the right hardware you need the right software and drivers too).

If you've passed the data up to a pixel shader unconverted, however, its easy to just swizzle the components as the shader does its normal thing (assuming that all textures suffer this affliction, that is).

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement