1

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

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

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

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

4

2 回答 2

2

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

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

至于您在标题中提出的问题,可以手动删除 Alpha 通道。诀窍是了解 GdkPixbuf 中的数据是如何存储的。当您有一个带有 alpha 通道(也称为 RGBA)的 RGB pixbuf 时,像素存储为 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 中的更多讨论,请参见此处。

于 2012-05-23T07:18:33.507 回答
-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;
    }
于 2012-05-24T02:28:39.440 回答