如何使用Cairo的CAIRO_FORMAT_RGBA128F进行32位颜色输出?

问题描述 投票:0回答:1

我目前正在使用 Cairo 进行 8 位渲染,并在 After Effects 插件中使用以下代码,使用 CAIRO_FORMAT_ARGB32 图像表面效果很好:

// 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;
}

但是,我希望能够使用 CAIRO_FORMAT_RGBA128F 图像表面,它使用 4 个浮点,因此允许更灵活的 32 位颜色。这里有关于此的信息:https://cairographics.org/manual/cairo-Image-Surfaces.html#cairo-format-t

问题是我尝试以多种不同的方式调整 8 位代码,但没有成功使用浮点数,不幸的是,我找不到任何有关如何使用此浮点图像表面的示例。我所做的任何尝试都会发生很多崩溃,我相信这部分是由于代码需要从根本上进行调整,但同样,没有任何现有的示例,这很难做到。

任何人都可以帮助使用 CAIRO_FORMAT_RGBA128F 图像表面的浮点数来调整下面的代码吗?

谢谢你。

c++ colors graphics cairo color-depth
1个回答
0
投票

我找不到任何有关如何使用此浮点图像表面的示例

我尝试了一下,结果似乎立即见效。该程序在图像表面随机绘制一些内容,然后打印其内容。一次通过 ARGB32 表面,一次通过 RGBA128F。

#include <cairo.h>
#include <stdio.h>
#include <stdint.h>

//! Draw something to the surface
static void fill_it(cairo_surface_t *s) {
    cairo_t *cr = cairo_create(s);

    cairo_set_source_rgb(cr, 1, 0.75, 0);
    cairo_paint(cr);

    cairo_rectangle(cr, 0, 0, 1, 1);
    cairo_set_source_rgb(cr, 0.5, 0, 0);
    cairo_fill(cr);

    cairo_rectangle(cr, 1, 0, 1, 1);
    cairo_set_source_rgb(cr, 0.3333, 1, 0);
    cairo_fill(cr);

    cairo_rectangle(cr, 0, 1, 1, 1);
    cairo_set_source_rgb(cr, 0, 0.1234, 1);
    cairo_fill(cr);

    cairo_destroy(cr);
}

static float uint8_to_float(uint8_t value) {
    return value * 1.0 / 255.0;
}

static void print_it_argb32(cairo_surface_t *s) {
    int width = cairo_image_surface_get_width(s);
    int height = cairo_image_surface_get_width(s);
    int stride = cairo_image_surface_get_stride(s);
    unsigned char* data = cairo_image_surface_get_data(s);

    for (int row = 0; row < height; row++) {
        for (int column = 0; column < width; column++) {
            uint32_t pixel = ((uint32_t*) data)[column];
            printf("Pixel r=%g g=%g b=%g a=%g\n", uint8_to_float(pixel >> 16), uint8_to_float(pixel >> 8), uint8_to_float(pixel), uint8_to_float(pixel >> 24));
        }
        data += stride;
    }
}

static void print_it_rgba128(cairo_surface_t *s) {
    int width = cairo_image_surface_get_width(s);
    int height = cairo_image_surface_get_width(s);
    int stride = cairo_image_surface_get_stride(s);
    unsigned char* data = cairo_image_surface_get_data(s);

    for (int row = 0; row < height; row++) {
        for (int column = 0; column < width; column++) {
            float* pixels = ((float*) data) + column * 4;
            printf("Pixel r=%g g=%g b=%g a=%g\n", pixels[0], pixels[1], pixels[2], pixels[3]);
        }
        data += stride;
    }
}

static void print_it(cairo_surface_t *s) {
    switch (cairo_image_surface_get_format(s)) {
    case CAIRO_FORMAT_ARGB32:
        return print_it_argb32(s);
    case CAIRO_FORMAT_RGBA128F:
        return print_it_rgba128(s);
    default:
        puts("Unsupported format");
    }
}

static void try_it(cairo_format_t format) {
    cairo_surface_t *s = cairo_image_surface_create(format, 2, 2);
    fill_it(s);
    print_it(s);
    cairo_surface_destroy(s);
    puts("");
}

int main() {
    try_it(CAIRO_FORMAT_ARGB32);
    try_it(CAIRO_FORMAT_RGBA128F);
}

任何人都可以帮助使用 CAIRO_FORMAT_RGBA128F 图像表面的浮点数来调整下面的代码吗?

嗯...随机猜测是:

// 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;
    float* rowP;
    PF_Pixel8* worldPtr = sampleIntegral8(data->output, 0, i);
    rowP = (float*)(data->data + i * data->stride);
    for (int x = 0; x < data->output.width; x++) {
        float red = rowP[4*x + 0];
        float green = rowP[4*x + 1];
        float blue = rowP[4*x + 2];
        float alpha = rowP[4*x + 3];
        worldPtr->alpha = alpha * 255.0;
        if (worldPtr->alpha)
        {
            float rf = red / alpha;
            float gf = green / alpha;
            float bf = blue / 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;
}

但请注意,我不知道这些行的一半应该是什么。

我添加了 alpha 乘以 255,因为我认为这是

PF_Pixel8
所期望的。至少之前似乎已经获得了该范围内的值。

颜色分量似乎不需要这样的乘法,因为除以 alpha 会自动校正不同的值范围。

© www.soinside.com 2019 - 2024. All rights reserved.