Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Kurles от Февраль 06, 2015, 10:52



Название: QPainter: сделать часть изображения прозрачным.
Отправлено: Kurles от Февраль 06, 2015, 10:52
Доброго времени суток!

Есть простая задача: в QImage определённый регион QRect сделать полностью прозрачным, удалив при этом предыдущий контент.

попробовал "очевидный" вариант:
Код
C++ (Qt)
       QImage img;
       QRect removedRect;
       // .. получаем картинку и вычисляем регион
       QPainter p(&img);
       p.fillRect(removedRect, Qt::transparent);
 
- и упс: тот контент, что был в том регионе, за кот. отвечает rect, остался на месте.
Полез в доку, нашёл 2 метода: void QPainter::setOpacity ( qreal opacity ) и void   setBackgroundMode ( Qt::BGMode mode ) Ура, думаю, оно! Установил opacity в 1., а backgroundMode в Qt::OpaqueMode. Но результат остался прежним :(
Пришлось идти на крайние (с моей точки зрения) меры: апдейтить значения пикселей вручную:

Код
C++ (Qt)
       int startX = removedRect.topLeft().x();
       for  (int i = 0; i < removedRect.height(); ++i) {
           uchar *scanline = img->scanLine(i);
           scanline += startX * 4;
           for (int x = 0; x < removedRect.width(); ++x) {
               *(scanline + x) = (uchar)0x00;
               *(scanline + x + 1) = (uchar)0x00;
               *(scanline + x + 2) = (uchar)0x00;
               *(scanline + x + 3) = (uchar)0x00;
           }
       }
 
Сиё поделие работает, но как то по мне, дык слишком низкоуровнево. Может кто подскажет, как достичь такого же результата с  помощью QPainter?


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: GreatSnake от Февраль 06, 2015, 11:02
Создай новый QImage и залей его Qt::transparent.
Потом задай через QPainter::setClipRegion() "дырку".
Потом через QPainter::drawImage() залей оригинальную картинку.

UPD. Достаточно перед рендерингом "дырку" залить Qt::transparent и уже с учётом неё задать clipping ( QRegion( image_rect ).subtracted( hole_rect ) ).


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Igors от Февраль 06, 2015, 11:06
Код
C++ (Qt)
       p.fillRect(removedRect, Qt::transparent);
 
Это должно работать. Проверьте что формат имеджа QImage::ARGB32. Иначе выложите тестовый проект


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: GreatSnake от Февраль 06, 2015, 11:09
Это должно работать.
Неа, не должно. Это тоже самое, как положить на холст картины позрачное стекло. ;)


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Kurles от Февраль 06, 2015, 11:29
Код
C++ (Qt)
       p.fillRect(removedRect, Qt::transparent);
 
Это должно работать. Проверьте что формат имеджа QImage::ARGB32. Иначе выложите тестовый проект
Формат QImage::Format_ARGB32_Premultiplied, не работает. Действительно, как прозрачное стекло накладывается. Для теста пробовал вместо Qt::transparent  Qt::red - закрашивает красным, всё ок.


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Kurles от Февраль 06, 2015, 11:31
Создай новый QImage и залей его Qt::transparent.
Потом задай через QPainter::setClipRegion() "дырку".
Потом через QPainter::drawImage() залей оригинальную картинку.

UPD. Достаточно перед рендерингом "дырку" залить Qt::transparent и уже с учётом неё задать clipping ( QRegion( image_rect ).subtracted( hole_rect ) ).
Ух ты блин, спасибо. Но довольно накладно по расходам, хотелось бы без создания временных изображений, пока остаюсь на своём варианте.


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: GreatSnake от Февраль 06, 2015, 11:33
Ух ты блин, спасибо. Но довольно накладно по расходам, хотелось бы без создания временных изображений, пока остаюсь на своём варианте.
Смотри в "UPD". Там именно так.


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Kurles от Февраль 06, 2015, 11:38
Код
C++ (Qt)
       p.fillRect(removedRect, Qt::transparent);
 
Это должно работать. Проверьте что формат имеджа QImage::ARGB32. Иначе выложите тестовый проект
Пожалуйста:
Код
C++ (Qt)
#include <QApplication>
#include <QLabel>
#include <QPainter>
#include <QImage>
 
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
 
   QImage img(QSize(500, 500), QImage::Format_ARGB32_Premultiplied);
   img.fill(Qt::green);
   {
       QPainter p(&img);
       p.fillRect(QRect(QPoint(0, 0), QSize(250, 250)), Qt::red);
       p.fillRect(QRect(QPoint(255, 255), QSize(250, 250)), Qt::transparent);
   }
   QLabel label;
   label.setPixmap(QPixmap::fromImage(img));
   label.show();
   return a.exec();
}
 


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Igors от Февраль 06, 2015, 11:54
Неа, не должно. Это тоже самое, как положить на холст картины позрачное стекло. ;)
Да, по умолчанию он альфу не реплейсит. Значит так ему по рогам

Код
C++ (Qt)
p.setCompositionMode(QPainter::CompositionMode_Clear);
p.fillRect(QRect(QPoint(255, 255), QSize(250, 250)), Qt::transparent);
 

А понятие "холст" давно устарело и употребляется только Верес'ом  :)


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: GreatSnake от Февраль 06, 2015, 11:57
А понятие "холст" давно устарело и употребляется только Верес'ом  :)
В своей ремарке я имел в виду настоящий холст ;)

Кстати, тоже была мысля через сomposition за-XOR-ить, но чего-то засомневался.


Название: Re: QPainter: сделать часть изображения прозрачным.
Отправлено: Kurles от Февраль 06, 2015, 12:36
Всем спасибо. Взял вариант с
Код
C++ (Qt)
p.setCompositionMode(QPainter::CompositionMode_Clear);