在开罗绘制图像时的不同颜色

Difference color when drawing image in Cairo

我在 linux 系统中使用 Cairo 绘制图像时遇到问题。如果使用 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

我很确定右图的红色和蓝色通道互换了。遗憾的是,我不知道 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。
  • 如果现在将字节向右循环一个位置,最终将交换红色和蓝色。

我还发现评论中用户@Bob__ 的link 非常有帮助:

Are you sure that the channels are stored in the expected order? See e.g. http://en.m.wikipedia.org/wiki/RGBA_color_model#Representation

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

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。谁能建议我其他解决方案?