我有一个小代码片段,它从PNG文件加载图像,然后通过使特定颜色透明来修改内存中的图像数据(将该颜色的alpha设置为0)。这是代码本身:
static gboolean expose (GtkWidget *widget, GdkEventExpose *event, gpointer userdata)
{
int width, height, stride, x, y;
cairo_t *cr = gdk_cairo_create(widget->window);
cairo_surface_t* image;
char* ptr;
if (supports_alpha)
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
else
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opaque white */
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
image = cairo_image_surface_create_from_png ("bg.png");
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
stride = cairo_image_surface_get_stride (image);
cairo_surface_flush (image);
ptr = (unsigned char*)malloc (stride * height);
memcpy (ptr, cairo_image_surface_get_data (image), stride * height);
cairo_surface_destroy (image);
image = cairo_image_surface_create_for_data (ptr, CAIRO_FORMAT_ARGB32, width, height, stride);
cairo_surface_flush (image);
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
char alpha = 0;
unsigned int z = *((unsigned int*)&ptr [y * stride + x * 4]);
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
}
}
cairo_surface_mark_dirty (image);
cairo_surface_write_to_png (image, "image.png");
gtk_widget_set_size_request (GTK_OBJECT (window), width, height);
gtk_window_set_resizable (GTK_OBJECT (window), FALSE);
cairo_set_source_surface (cr, image, 0, 0);
cairo_paint_with_alpha (cr, 0.9);
cairo_destroy (cr);
cairo_surface_destroy (image);
free (ptr);
return FALSE;
}
当我将修改后的数据转储到PNG时,实际上就存在透明度。但是当相同的数据被用作绘画的源表面时,没有透明度。什么可能是错的?
附件:
答案 0 :(得分:4)
将alpha设置为0表示颜色完全透明。由于cairo使用预乘的alpha,因此必须将像素设置为0,否则颜色分量的值可能高于alpha通道。我认为cairo会对那些超级发光的像素感到窒息。
所以代替这段代码:
if ((z & 0xffffff) == 0xffffff) {
z = (z & ~0xff000000) | (alpha & 0xff000000);
*((unsigned int*) &ptr [y * stride + x * 4]) = z;
}
您应该尝试以下方法:
if ((z & 0xffffff) == 0xffffff) {
*((unsigned int*) &ptr [y * stride + x * 4]) = 0;
}
虽然我们在这里:
(z & 0xffffff) == 0xffffff
检查绿色,蓝色和Alpha通道是否全部为100%并忽略红色通道?你确定这真的是你想要的吗? z == 0xffffffff
将是不透明的白色。unsigned int
来访问像素数据,那么最好不要使用uint32_t
。便携!cairo_image_surface_create_from_png()
始终为您提供格式为ARGB32的图像表面。我认为这不一定总是正确的,例如RGB24也是可能的。我想我会这样做:
for (y = 0; y < height; y++) {
uint32_t row = (uint32_t *) &ptr[y * stride];
for (x = 0; x < width; x++) {
uint32_t px = row[x];
if (is_expected_color(px))
row[x] = 0;
}
}