Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
1

Cairo 16 bit & 32 bit Rendering (SDK)

Engaged ,
Nov 03, 2024 Nov 03, 2024

Hi gang!

 

I know there are a few developers on here using Cairo with the AE SDK and I have recently jumped into this as well. It is indeed quite powerful and makes life significantly easier.

 

One thing I can't figure out is how to render in other depths like 16 bit and 32 bit. This is the familiar code for rendering in 8-bit from Cairo:

 

// Write pixel 8-bit
PF_Pixel* sampleIntegral8(PF_EffectWorld& def, int x, int y) {
    return (PF_Pixel*)((char*)def.data +
        (y * def.rowbytes) +
        (x * sizeof(PF_Pixel)));
}

PF_Err cairoCopy8(void* refcon, A_long threadInd, A_long itemNum,
    A_long iterTotal)
{
    cairoRefcon* data = (cairoRefcon*)refcon;
    int i = itemNum;
    PF_Err err = PF_Err_NONE;
    uint32_t* rowP;
    PF_Pixel8* worldPtr = sampleIntegral8(data->output, 0, i);
    rowP = (uint32_t*)(data->data + i * data->stride);
    for (int x = 0; x < data->output.width; x++) {
        worldPtr->alpha = rowP[x] >> 24;
        if (worldPtr->alpha)
        {
            float rf = A_u_char(rowP[x] >> 16) / (float)worldPtr->alpha;
            float gf = A_u_char(rowP[x] >> 8) / (float)worldPtr->alpha;
            float bf = A_u_char(rowP[x] >> 0) / (float)worldPtr->alpha;
            worldPtr->red = A_u_char(rf * PF_MAX_CHAN8);
            worldPtr->green = A_u_char(gf * PF_MAX_CHAN8);
            worldPtr->blue = A_u_char(bf * PF_MAX_CHAN8);
        }
        worldPtr++;
    }

    return err;
}

 

This is what I've done in my *attempt* to adapt it to 16-bit rendering:

 

PF_Pixel16* sampleIntegral16(PF_EffectWorld& def, int x, int y) {
    return (PF_Pixel16*)((char*)def.data +
        (y * def.rowbytes) +
        (x * sizeof(PF_Pixel16)));
}

PF_Err cairoCopy16(void* refcon, A_long threadInd, A_long itemNum,
    A_long iterTotal)
{
    cairoRefcon* data = (cairoRefcon*)refcon;
    int i = itemNum;
    PF_Err err = PF_Err_NONE;
    uint32_t* rowP;
    PF_Pixel16* worldPtr = sampleIntegral16(data->output, 0, i);
    rowP = (uint32_t*)(data->data + i * data->stride);
    for (int x = 0; x < data->output.width; x++) {
        worldPtr->alpha = rowP[x] >> 24;
        if (worldPtr->alpha)
        {
            float rf = A_u_char(rowP[x] >> 16) / (float)worldPtr->alpha;
            float gf = A_u_char(rowP[x] >> 8) / (float)worldPtr->alpha;
            float bf = A_u_char(rowP[x] >> 0) / (float)worldPtr->alpha;
            worldPtr->red = A_u_char(rf * PF_MAX_CHAN16);
            worldPtr->green = A_u_char(gf * PF_MAX_CHAN16);
            worldPtr->blue = A_u_char(bf * PF_MAX_CHAN16);
        }
        worldPtr++;
    }

    return err;
}

 

However, this renders incorrectly. It seems it still exports in the range of 0-255. Perhaps it has something to do with the bit-shifting which may need to be different for 16 / 32 bit and which, admittedly, I don't really understand.

 

Does anyone have any ideas on how to correctly adapt this to 16-bit and 32-bit?

 

Thank you as always in advance to everyone. Without this forum, I'd get nowhere.

 

Regards,

-Richard

TOPICS
SDK
365
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Engaged , Nov 08, 2024 Nov 08, 2024

Here's the 16bpc version I use, credit to the author of the ink effect plugin that was on the old AESDK forums:

PF_Err cairoCopy16(void *refcon, A_long threadInd, A_long iterNum, A_long iterTotal)
{
	cairoRefcon *data = (cairoRefcon*)refcon;

	int i = iterNum;

	PF_Err err = PF_Err_NONE;

	uint32_t *rowP;

	PF_Pixel8 world8;

	PF_Pixel16 *worldPtr = sampleIntegral16(*data->output, 0, i);

	rowP = (uint32_t *)(data->data + i * data->stride);

	for (int x = 0; x < data->output->width; x++) // colum
...
Translate
Community Expert ,
Nov 03, 2024 Nov 03, 2024

i never user cairo, but this is what pops into mind at a glance:

in the folowing row i see a couple of problems.

float rf = A_u_char(rowP[x] >> 16) / (float)worldPtr->alpha;

1. casting to A_u_char limits the value to 0-255 range. a PF_Pixel16 uses A_u_short for it's channels.

2. bitshifting the channels by multiples of 8 is correct for 8 bits. for 16 bits you should bitshift by multiples of 16.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2024 Nov 04, 2024

Hi Shachar;

 

Thanks for your always helpful suggestions.

 

Thanks for pointing out the A_u_char - I should have known that is limited to 255, and that was my careless mistake.

 

The 16 bit shift, I would not have understood. I tried those suggestions but unfortunately, the output is still wrong. It outputs all channels but they are wrong - the alpha is aliased and the RGB channels display incorrect colors. This is the adapted code I used as per your suggestions:

 

 

 

PF_Err cairoCopy16(void* refcon, A_long threadInd, A_long itemNum,
	A_long iterTotal)
{
	cairoRefcon* data = (cairoRefcon*)refcon;
	int i = itemNum;
	PF_Err err = PF_Err_NONE;
	uint32_t* rowP;
	PF_Pixel16* worldPtr = sampleIntegral16(data->output, 0, i);
	rowP = (uint32_t*)(data->data + i * data->stride);
	for (int x = 0; x < data->output.width; x++) {
		worldPtr->alpha = rowP[x] >> 48;
		if (worldPtr->alpha)
		{
			float rf = A_u_short(rowP[x] >> 32) / (float)worldPtr->alpha;
			float gf = A_u_short(rowP[x] >> 16) / (float)worldPtr->alpha;
			float bf = A_u_short(rowP[x] >> 0) / (float)worldPtr->alpha;
			float af = A_u_short(rowP[x] >> 48) / (float)PF_MAX_CHAN16;
			worldPtr->red = A_u_short(rf * PF_MAX_CHAN16);
			worldPtr->green = A_u_short(gf * PF_MAX_CHAN16);
			worldPtr->blue = A_u_short(bf * PF_MAX_CHAN16);
			worldPtr->alpha = A_u_short(af * PF_MAX_CHAN16);
		}
		worldPtr++;
	}

	return err;
}

 

 

 

Anyway, I understand if you are unfamiliar with Cairo, you might not have much else to suggest but perhaps someone who uses it might know?

 

I assume Cairo supports 16 bit and 32 bit - I would be very, very surprised if it didn't. The only other thing I can think might be a culprit is the image format one specifies at the beginning:

 

 

 

cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, output->width, output->height);

 

 

 

Looking in the docs, this is what they say about the image formats: https://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t

 

Actually, the above suggests that the CAIRO_FORMAT_ARGB32 is a 8-bits per channel format? And I don't see any other formats that suggest higher bit depths... Am I nuts? There is the "CAIRO_FORMAT_RGB16_565" but that seems to carry less information than the ARGB32 so I don't see how that could be 16 bits per channel. However, I don't see how Cairo could only offer 8 bit color depth so perhaps I'm missing something here...

 

*EDIT*

 

I do see that it offers the option to use "CAIRO_FORMAT_RGBA128F" which is 32 bit. Perhaps this is one option to go with. It wasn't in my version of Cairo but a newer one.

 

-Richard

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 08, 2024 Nov 08, 2024

Here's the 16bpc version I use, credit to the author of the ink effect plugin that was on the old AESDK forums:

PF_Err cairoCopy16(void *refcon, A_long threadInd, A_long iterNum, A_long iterTotal)
{
	cairoRefcon *data = (cairoRefcon*)refcon;

	int i = iterNum;

	PF_Err err = PF_Err_NONE;

	uint32_t *rowP;

	PF_Pixel8 world8;

	PF_Pixel16 *worldPtr = sampleIntegral16(*data->output, 0, i);

	rowP = (uint32_t *)(data->data + i * data->stride);

	for (int x = 0; x < data->output->width; x++) // column
	{
		world8.alpha = rowP[x] >> 24;

		if (world8.alpha > 0)
		{
			world8.red = rowP[x] >> 16;
			world8.green = rowP[x] >> 8;
			world8.blue = rowP[x];

			worldPtr->red = A_u_short(double((PF_MAX_CHAN8 * world8.red) / world8.alpha) * 128.50196);
			worldPtr->green = A_u_short(double((PF_MAX_CHAN8 * world8.green) / world8.alpha) * 128.50196);
			worldPtr->blue = A_u_short(double((PF_MAX_CHAN8 * world8.blue) / world8.alpha) * 128.50196);
			worldPtr->alpha = A_u_short(double(world8.alpha * 128.50196));
		}

		worldPtr++;
	}

	return err;
}

If you make the plugin 32bpc (even though the cairo format may be 8bpc) you don't need to deal with 16bpc, AE will just give you a 32bpc buffer and do the 32 -> 16 conversion for you. Really handy!

 

The newer versions of cairo also have 32bpc support but was so difficult to compile I outsourced it as I couldn't figure it out. 

 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 09, 2024 Nov 09, 2024
LATEST

Hi ya James!

 

Thanks very much for your help - this does indeed work fine. However, correct me if I'm wrong, but isn't this just scaling an 8-bit color to 16-bit? So Cairo isn't actually providing a true 16-bit pixel in the case above?

 

Funny regarding your last comment - I too noticed the Cairo floating point color support and of course, it was in a newer version than the one I had. So I tried to download all the latest Cairo pieces and compile them on my own as well and, just like you, I got absolutely nowhere. It's a real hot mess, with little to no information, and an absolute nightmare to get to work. It refused to compile correctly no matter what I tired. So in the end I gave up on it! lol

 

So your 16-bit support is at least welcome for now until I can solve that later on. These plugins aren't 32-bit plugins anyway so this will do.

 

But to clarify, you're saying if I start from a SmartFX plugin I don't need to worry about the 16 bit support as it will automatically output it if in 16-bit mode? That means though, I would need to get the latest Cairo version working in order to use its 32-bit floating point color capabilities.

 

Thanks again for your help!

 

Also, you mentioned you found this tidbit in the old AE forum - is there an actual way to access that? It was my understanding that it was mercilessly long blown away by Adobe. Such a shame as there was SO much helpful info on there...

 

Regards,

-Rich

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines