如何删除(或应用)gdk-pixbuf上的透明度?

时间:2010-04-30 11:21:47

标签: c++ gdk

我有一个c ++程序,其中创建了一个gdk-pixbuf。我想将其输出为图像,因此我调用gdk_pixbuf_save_to_stream(pixbuf,stream,type,NULL,&err,NULL)。当“type”是png或tiff时,这可以正常工作,但是使用jpeg或bmp它只会产生一个黑色方块。原始pixbuf由黑色透明(和gdk_pixbuf_get_has_alpha返回true)组成,所以我猜测问题是alpha掩码。

GdkPixbuf有一个添加alpha通道的功能,但我看不到再次删除它,或者(可能同样好)将其反转。

是否有一种简单的方法可以让jpeg和bmp格式正常工作?

(我应该说我对这样的正确编程很新。)

2 个答案:

答案 0 :(得分:2)

JPEG没有任何alpha通道或透明度的概念。在转换为JPEG期间,Alpha通道被剥离。 BMP也有同样的限制。

由于透明度对您很重要,因此您的程序应该坚持生成PNG。

就标题中提出的问题而言,删除Alpha通道可以手动完成。诀窍是了解GdkPixbuf中的数据是如何存储的。当你有一个带有alpha通道的RGB pixbuf(也称为RGBA)时,像素存储为32位值:4个字节,每个颜色一个字节,第四个是alpha通道。 RGB pixbuf存储为24位值,每种颜色一个字节。

因此,如果您创建一个临时字节缓冲区并复制每个RGBA像素的前三个字节并删除第四个字节,那么该临时缓冲区就是纯RGB。略图一下:

[R] [G] [B] [A] [R] [G] [B] [A] ... => [R] [G] [B] [R] [G] [B] ...

请注意,您必须打包临时缓冲区; [B]字节和下一个[R]字节之间没有备用字节。

然后通过将此RGB缓冲区交给它来创建一个新的GdkPixbuf,并删除了alpha通道。

请参阅gdk_pixbuf_get_pixels()以访问RGBA缓冲区和gdk_pixbuf_new_from_data()以创建RGB pixbuf。有关如何将打包数据存储在GdkPixbuf中的更多讨论,请参阅here

答案 1 :(得分:-1)

这是(相当低效和丑陋)Vala应用程序,它从图像中删除透明度并以指定的格式保存。注意:gdk_pixbuf_new_from_data()的vala绑定中存在一个小错误,导致生成的图像损坏。我很快就会解决这个问题,但这暂时是为了演示目的(除了问题是关于C ++):

    public static int main (string[] args) {
        if (args.length < 4) {
            print ("Usage: %s SOURCE DESTINATION FORMAT\n", args[0]);
            return -1;
        }

        var src_path = args[1];
        var destination_path = args[2];
        var dest_type = args[3];

        var pixbuf = new Gdk.Pixbuf.from_file_at_scale (src_path, 48, 48, false);

        // Remove alpha channel
        if (pixbuf.get_has_alpha () && pixbuf.get_n_channels () == 4 && pixbuf.get_bits_per_sample () == 8) {
            var width = pixbuf.get_width ();
            var height = pixbuf.get_height ();
            var rowstride = pixbuf.get_rowstride ();
            unowned uint8[] orig_pixels = pixbuf.get_pixels ();
            var pixels = new uint8[rowstride * height];

            for (var i = 0; i < height; i++) {
                for (var j = 0, k = 0; j < width * 4; j += 4, k += 3) {
                    var orig_index = rowstride * i + j;
                    var index = rowstride * i + k;

                    if (orig_pixels[orig_index] == 0 &&
                        orig_pixels[orig_index + 1] == 0 &&
                        orig_pixels[orig_index + 2] == 0 &&
                        orig_pixels[orig_index + 3] == 0) {
                        pixels[index] = 0xFF;
                        pixels[index + 1] = 0xFF;
                        pixels[index + 2] = 0xFF;
                    } else {
                        pixels[index] = orig_pixels[orig_index];
                        pixels[index + 1] = orig_pixels[orig_index + 1];
                        pixels[index + 2] = orig_pixels[orig_index + 2];
                    }
                }
            }

            pixbuf = new Gdk.Pixbuf.from_data (pixels,
                                               pixbuf.get_colorspace (),
                                               false,
                                               8,
                                               width,
                                               height,
                                               rowstride,
                                               null);
        }

        pixbuf.save (destination_path, dest_type);

        return 0;
    }