Как удалить (или применить) прозрачность в gdk-pixbuf? - PullRequest
1 голос
/ 30 апреля 2010

У меня есть программа на С ++, в которой создается 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), поэтому я догадываюсь , что проблема в альфа-маске.

GdkPixbuf имеет функцию для добавленияальфа-канал, но я не вижу того, который удаляет его снова или (что может быть так же хорошо) инвертировать его.

Есть ли простой способ заставить форматы jpeg и bmp работать должным образом?

(Я должен сказать, что я очень новичок в правильном программировании, подобном этому.)

Ответы [ 2 ]

2 голосов
/ 23 мая 2012

JPEG не имеет никакого понятия об альфа-канале или прозрачности вообще. Альфа-канал обрезается во время преобразования в JPEG. BMP имеет такое же ограничение.

Поскольку прозрачность важна для вас, ваша программа должна придерживаться генерации PNG.

Что касается вопроса, который вы задали в заголовке, удаление альфа-канала можно выполнить вручную. Хитрость заключается в понимании того, как хранятся данные в GdkPixbuf. Если у вас есть RGB pixbuf с альфа-каналом (также называемый RGBA), пиксели сохраняются в виде 32-битных значений: 4 байта, один байт на цвет, четвертый - альфа-канал. Пиксельные буферы RGB хранятся в виде 24-битных значений, по одному байту на цвет.

Итак, если вы создаете временный байтовый буфер и копируете первые три байта каждого пикселя RGBA и отбрасываете четвертый, тогда этот временный буфер будет чисто RGB. Чтобы представить это немного:

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

Обратите внимание, что вы должны упаковать временный буфер; между байтом [B] и следующим байтом [R] нет запасного байта.

Затем вы создаете новый GdkPixbuf, передавая ему этот буфер RGB, и вы удаляете альфа-канал.

См. Gdk_pixbuf_get_pixels () для доступа к буферу RGBA и gdk_pixbuf_new_from_data () для создания пиксельного буфера RGB. См. здесь для получения дополнительной информации о том, как упакованные данные хранятся в GdkPixbuf. * ​​1017 *

0 голосов
/ 24 мая 2012

Вот (довольно неэффективное и уродливое) приложение Vala, которое удаляет прозрачность с изображения и сохраняет его в указанном формате. ПРИМЕЧАНИЕ. Существует небольшая ошибка в привязке vala для gdk_pixbuf_new_from_data (), которая приводит к повреждению полученного изображения. Я собираюсь исправить это в ближайшее время, но это пока только для демонстрационных целей (кроме вопроса о 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;
    }
...