【问题标题】:Difference color when drawing image in Cairo在开罗绘制图像时的颜色差异
【发布时间】:2021-06-18 05:00:36
【问题描述】:

我在使用 Cairo 在 linux 系统中绘制图像时遇到问题。如果使用 cairo_image_surface_create 方法,输出图像颜色与原始图像不相似。如下代码:

int width, height, channels;
unsigned char* data = stbi_load(imagePath.c_str(), &width, &height, &channels, STBI_rgb_alpha);
this->imageSource = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
unsigned char * surface_data = cairo_image_surface_get_data(this->imageSource);
memcpy(surface_data, data, width * height * 4 * sizeof(unsigned char));
cairo_surface_mark_dirty(this->imageSource);
free(data);

但使用 cairo_image_surface_create_from_png 时颜色会相同(此 api 仅支持 png 格式)。看我的代码如下:

this->imageSource = cairo_image_surface_create_from_png(imagePath.c_str());

还可以清楚地查看附加图像。

enter image description here

【问题讨论】:

  • 您确定频道按预期顺序存储吗?参见例如en.m.wikipedia.org/wiki/RGBA_color_model#Representation
  • 嗨,关于图像通道,我正在使用 stb_image 从结构为 32 位 (RGBA) 的文件中读取图像,但我也重新排序为 ARGB32,我得到的图像仍然与原始图像不同。
  • 请注意,原始图像是PNG,位深度=24(RGB)。在这种情况下,我把 alpha 值默认为 255

标签: c++ linux cairo


【解决方案1】:

我很确定红色和蓝色通道在正确的图像上交换了。遗憾的是,我不知道 STBI_rgb_alpha 是什么,而且 Google 没有找到任何看起来有用的文档,所以:

  • Cairo 将每个像素存储为 uint32_t,alpha 在高字节,蓝色在低字节,即uint32_t pixel_value = alpha << 24 | red << 16 | green << 8 | blue;
  • 这意味着内存中字节的实际顺序取决于系统字节序。
  • 我猜STBI_rgb_alpha 表示这些值是按字节保存的,与系统字节序无关。
  • 因此,cairo 期望字节按 b、g、r、a 的顺序排列,而 stbi 使用 r、g、b、a。
  • 如果您现在将字节向右循环一个位置,您最终会交换红色和蓝色。

我还发现 cmets 中用户 @Bob__ 的链接非常有用:

您确定频道按预期顺序存储吗?参见例如http://en.m.wikipedia.org/wiki/RGBA_color_model#Representation

【讨论】:

  • 亲爱的 Uli Schlachter 和 Bob__,问题已解决。非常感谢您的支持。
【解决方案2】:

现在使用正确的通道绘制图像,但它花费更多时间重新排序像素数据通道。你们都可以建议其他方法来节省这种情况下的处理时间吗?请参阅下面的代码:

int width, height, channels;
//imagePath: [string] is input path of image on disk
unsigned char* data = stbi_load(imagePath.c_str(), &width, &height, &channels, STBI_rgb_alpha);
int size = width * height * 4;
uint32_t * dest_data = ( uint32_t * ) malloc(sizeof( uint32_t ) * width * height);
int i;
int dest_index = 0;
uint8_t *pixel, alpha, red, green, blue;
uint32_t p;
//***important: re-order pixel data after receive from stbi_load 
for (i = 0; i < size; i += 4) {
    pixel = &data [ i ];
    alpha = pixel [ 3 ];
    if (alpha == 0) {
        p = 0;
    } else {
        red = pixel [ 0 ];
        green = pixel [ 1 ];
        blue = pixel [ 2 ];
        if (alpha != 0xff) {
            red = multiply_alpha(alpha, red);
            green = multiply_alpha(alpha, green);
            blue = multiply_alpha(alpha, blue);
        }
        p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
    }
    dest_data [ dest_index ] = p;
    dest_index++;
}

//create new surface instance
this->imageSource = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
unsigned char * surface_data = cairo_image_surface_get_data(this->imageSource);
//map image data to surface
memcpy(surface_data, dest_data, width * height * 4 * sizeof(unsigned char));
//mark dirty to call reload surface
cairo_surface_mark_dirty(this->imageSource);

//free memory
free(dest_data);
free(data);

当我阅读 stb_image 库时,在函数 stbi_load 中没有参数调用 ORDER。谁能建议我其他解决方案?

【讨论】:

  • 没有人会在这里寻找您的新问题
猜你喜欢
  • 2010-09-14
  • 2016-09-21
  • 2012-08-15
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多