Copy link to clipboard
Copied
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
1 Correct answer
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
...
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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

