Render QGraphicsEffect into pixmap?



  • Hello World!

    I have a scene with a lot of items, all can have a custom QGraphicsEffects added.
    Once an effect is rendered I would like to save the result, and add the resulting
    qPixmap to a qPixmapCache.

    I was hoping to use the paint() function in my custom effect class, and in this do something ala
    @
    QPixmap im(loading the actual image);
    QPainter p(&im);
    QGraphicsDropShadowEffect::draw(&p);
    im.save("ImageShadow.png","png");
    @
    BUT (and I tried a lot o variants).. yeah you know .. no.

    I know that scene->render() may give me a copy of the result, but the item and its effects may very well be occluded/overlapped/.. so the optimal solution would be to 'grap' it once when (OR while) rendered.

    Anyone who saved effects? OR rendered effects into Qimage/pixmap/..?

    A lovely one to you!
    /bb



  • I've done it in the past by grabbing the widget

    QPixmap QPixmap::grabWidget ( QWidget * widget, const QRect & rectangle )

    I think you could specify the QRect to fit your entire scene. Have you given this a shot?



  • .. thanxx for the reply .. But as I understand this, it is basically the same as scene->render(..)? Using 'grabWidget' in a view/scene setup I have to do:

    pm = QPixmap::grabWidget(&view, x,y,w,h);

    But this is identical (or the result is) to scene.render(..), and my scene is stuffed with items, so this gives me the same 'overlapping' problems ..

    I could add a QLabel to my scene, and then use this as the widget for the 'grabWidget'. But how do I add my graphicsEffect to the widgets pixmap, and not the widget itself? .. hmm and I would really like to, not, include a QLabel in the scene ..



  • Hello i'm using QGraphicsEffect as a ThumbnailCollector here is my draw event,

    @
    void ThumbnailCollector::draw(QPainter *painter)
    {
    QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates);
    //pixmap will give to you your item its own pixmap data
    ...
    ...
    ...
    Q_EMIT thumbnailChanged(m_thumbnail);
    setEnabled(false);
    }
    @

    Hope this will help, but i have some flicking problems with that trying to solve that :s



  • QWidget::grab() is again regression for graphics effect, but graphics scene's render() call works like a charm without the need to create any widgets. Here is how:

    @ QImage applyEffectToImage(QImage src, QGraphicsEffect effect, int extent)
    {
    if(src.isNull()) return QImage(); //No need to do anything else!
    if(!effect) return src; //No need to do anything else!
    QGraphicsScene scene;
    QGraphicsPixmapItem item;
    item.setPixmap(QPixmap::fromImage(src));
    item.setGraphicsEffect(effect);
    scene.addItem(&item);
    QImage res(src.size()+QSize(extent
    2, extent2), QImage::Format_ARGB32);
    res.fill(Qt::transparent);
    QPainter ptr(&res);
    scene.render(&ptr, QRectF(), QRectF( -extent, -extent, src.width()+extent
    2, src.height()+extent*2 ) );
    return res;
    }@

    Them, using this function to is straightforward. Blur:

    @ QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
    blur->setBlurRadius(8);
    QImage source("://img1.png");
    QImage result = applyEffectToImage(source, blur);
    result.save("final.png");@

    Drop shadow:

    @ QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
    e->setColor(QColor(40,40,40,245));
    e->setOffset(0,10);
    e->setBlurRadius(50);
    QImage p("://img3.png");
    QImage res = applyEffectToImage(p, e, 40);@

    And note the extent parameter, it adds extent number of pixels to all sides of the original image, especially useful for shadows and blurs to not be cut-off.



  • QWidget::grab() is again regression for graphics effect, but graphics scene's render() call works like a charm without the need to create any widgets. Here is how:

    @ QImage applyEffectToImage(QImage src, QGraphicsEffect effect, int extent)
    {
    if(src.isNull()) return QImage(); //No need to do anything else!
    if(!effect) return src; //No need to do anything else!
    QGraphicsScene scene;
    QGraphicsPixmapItem item;
    item.setPixmap(QPixmap::fromImage(src));
    item.setGraphicsEffect(effect);
    scene.addItem(&item);
    QImage res(src.size()+QSize(extent
    2, extent2), QImage::Format_ARGB32);
    res.fill(Qt::transparent);
    QPainter ptr(&res);
    scene.render(&ptr, QRectF(), QRectF( -extent, -extent, src.width()+extent
    2, src.height()+extent*2 ) );
    return res;
    }@

    Them, using this function to is straightforward. Blur:

    @ QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
    blur->setBlurRadius(8);
    QImage source("://img1.png");
    QImage result = applyEffectToImage(source, blur);
    result.save("final.png");@

    Drop shadow:

    @ QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
    e->setColor(QColor(40,40,40,245));
    e->setOffset(0,10);
    e->setBlurRadius(50);
    QImage p("://img3.png");
    QImage res = applyEffectToImage(p, e, 40);@

    And note the extent parameter, it adds extent number of pixels to all sides of the original image, especially useful for shadows and blurs to not be cut-off.



  • You should render it, to do that you should override the paint function
    try this class:
    DropShadow.h

    @
    #ifndef DROPSHADOW_H
    #define DROPSHADOW_H
    #include <QtGui>
    #include <QtCore>
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QGraphicsEffect>
    #include <QtQuick/QQuickPaintedItem>
    #include <QLabel>
    #include <QPainter>
    #include <QGraphicsProxyWidget>
    /*!

    • \brief The DropShadow class, it load an Image and apply to it a DropShadow effect
      */
      class DropShadow : public QQuickPaintedItem
      {
      Q_OBJECT
      Q_PROPERTY(QString source READ getImageSource WRITE setImageSource)
      Q_PROPERTY(QColor color READ getColor WRITE setColor)
      Q_PROPERTY(int width READ getWidth WRITE setCustomWidth)
      Q_PROPERTY(int height READ getHeight WRITE setCustomHeight)
      Q_PROPERTY(double radius READ getBlurRadius WRITE setBlurRadius)
      Q_PROPERTY(double horizontalOffset READ getXOffset WRITE setXOffset)
      Q_PROPERTY(double verticalOffset READ getYOffset WRITE setYOffset)
      public:
      DropShadow(QQuickItem *parent = 0);
      int getWidth();
      int getHeight();
      void setCustomWidth(int width);
      void setCustomHeight(int height);
      void setImageSource(QString myImage);
      QString getImageSource() const;
      QColor getColor() const;
      void setColor(const QColor &color);
      double getBlurRadius() const;
      void setBlurRadius(const double blurRadius);
      double getXOffset() const;
      double getYOffset() const;
      void setXOffset(double value);
      void setYOffset(double value);
      void paint(QPainter *painter);
      ~DropShadow();
      signals:
      void sgnSourceImageChanged();

    public slots:
    void sltOnsourceChanged();
    private:
    QImage myImage;
    QString sourceImage;
    QColor m_color;
    double radius;
    QGraphicsDropShadowEffect
    pShadow;
    QGraphicsOpacityEffect* pOpacity;
    QGraphicsView view;
    QGraphicsScene *scene;
    int width;
    int height;
    QPixmap pixmap;
    QPainter * m_painter;
    double horizontalOffset;
    double verticalOffset;
    };
    #endif // DROPSHADOW_H
    @

    dropShadow.cpp

    @
    #include "dropshadow.h"
    DropShadow::DropShadow(QQuickItem *parent) :
    QQuickPaintedItem(parent)
    {

    connect(this,SIGNAL(sgnSourceImageChanged()),this,SLOT(sltOnsourceChanged()));
    myImage = new QImage;
    pShadow = new QGraphicsDropShadowEffect;
    m_color = Qt::blue;
    width = 0;
    height = 0;
    radius = 1.0;
    horizontalOffset = 8.0;
    verticalOffset = 8.0;
    scene = new QGraphicsScene;
    view.setScene(scene);
    

    }
    int DropShadow::getWidth()
    {
    return width;
    }
    int DropShadow::getHeight()
    {
    return height;
    }
    void DropShadow::setCustomWidth(int value)
    {
    width = value;
    qDebug()<<"DropShadow::setCustomWidth("<<value<<")";
    }
    void DropShadow::setCustomHeight(int value)
    {
    height = value;
    qDebug()<<"DropShadow::setCustomHeight("<<value<<")";
    }
    QColor DropShadow::getColor() const
    {
    return m_color;
    }
    void DropShadow::setColor(const QColor &color)
    {
    m_color = color;
    }
    double DropShadow::getBlurRadius() const
    {
    return radius;
    }
    double DropShadow::getXOffset() const
    {
    return horizontalOffset;
    }
    double DropShadow::getYOffset() const
    {
    return verticalOffset;
    }
    void DropShadow::setXOffset(double value)
    {
    horizontalOffset = value;
    }
    void DropShadow::setYOffset(double value)
    {
    verticalOffset = value;
    }
    void DropShadow::setBlurRadius(const double blurRadius)
    {
    radius = blurRadius;
    }
    void DropShadow::setImageSource(QString image)
    {
    sourceImage = image;
    sgnSourceImageChanged();
    }
    QString DropShadow::getImageSource() const
    {
    return sourceImage;
    }
    void DropShadow::sltOnsourceChanged()
    {
    myImage->load(sourceImage);
    if(width == 0)
    {
    width = myImage->width();
    }
    if(height == 0)
    {
    height = myImage->height();
    }
    this->setWidth(width);
    this->setHeight(height);
    pixmap = QPixmap::fromImage( myImage->scaled(width,height,Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
    }
    void DropShadow::paint(QPainter *painter)
    {
    view.setScene(scene);
    scene->setSceneRect(QRect(0,0,800,480));
    pShadow->setColor(QColor(m_color));
    pShadow->setBlurRadius(radius);
    pShadow->setXOffset(horizontalOffset);
    pShadow->setYOffset(verticalOffset);
    QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap);
    p->setGraphicsEffect(pShadow);
    view.render(painter,QRect(0,0,800,480),QRect(0,0,800,480));
    }
    DropShadow::~DropShadow()
    {
    delete myImage;
    delete pShadow;
    delete scene;
    }
    @

    [edit: added missing coding tags @ SGaist]



  • You should render it, to do that you should override the paint function
    try this class:
    DropShadow.h

    @
    #ifndef DROPSHADOW_H
    #define DROPSHADOW_H
    #include <QtGui>
    #include <QtCore>
    #include <QGraphicsView>
    #include <QGraphicsScene>
    #include <QGraphicsEffect>
    #include <QtQuick/QQuickPaintedItem>
    #include <QLabel>
    #include <QPainter>
    #include <QGraphicsProxyWidget>
    /*!

    • \brief The DropShadow class, it load an Image and apply to it a DropShadow effect
      */
      class DropShadow : public QQuickPaintedItem
      {
      Q_OBJECT
      Q_PROPERTY(QString source READ getImageSource WRITE setImageSource)
      Q_PROPERTY(QColor color READ getColor WRITE setColor)
      Q_PROPERTY(int width READ getWidth WRITE setCustomWidth)
      Q_PROPERTY(int height READ getHeight WRITE setCustomHeight)
      Q_PROPERTY(double radius READ getBlurRadius WRITE setBlurRadius)
      Q_PROPERTY(double horizontalOffset READ getXOffset WRITE setXOffset)
      Q_PROPERTY(double verticalOffset READ getYOffset WRITE setYOffset)
      public:
      DropShadow(QQuickItem *parent = 0);
      int getWidth();
      int getHeight();
      void setCustomWidth(int width);
      void setCustomHeight(int height);
      void setImageSource(QString myImage);
      QString getImageSource() const;
      QColor getColor() const;
      void setColor(const QColor &color);
      double getBlurRadius() const;
      void setBlurRadius(const double blurRadius);
      double getXOffset() const;
      double getYOffset() const;
      void setXOffset(double value);
      void setYOffset(double value);
      void paint(QPainter *painter);
      ~DropShadow();
      signals:
      void sgnSourceImageChanged();

    public slots:
    void sltOnsourceChanged();
    private:
    QImage myImage;
    QString sourceImage;
    QColor m_color;
    double radius;
    QGraphicsDropShadowEffect
    pShadow;
    QGraphicsOpacityEffect* pOpacity;
    QGraphicsView view;
    QGraphicsScene *scene;
    int width;
    int height;
    QPixmap pixmap;
    QPainter * m_painter;
    double horizontalOffset;
    double verticalOffset;
    };
    #endif // DROPSHADOW_H
    @

    dropShadow.cpp

    @
    #include "dropshadow.h"
    DropShadow::DropShadow(QQuickItem *parent) :
    QQuickPaintedItem(parent)
    {

    connect(this,SIGNAL(sgnSourceImageChanged()),this,SLOT(sltOnsourceChanged()));
    myImage = new QImage;
    pShadow = new QGraphicsDropShadowEffect;
    m_color = Qt::blue;
    width = 0;
    height = 0;
    radius = 1.0;
    horizontalOffset = 8.0;
    verticalOffset = 8.0;
    scene = new QGraphicsScene;
    view.setScene(scene);
    

    }
    int DropShadow::getWidth()
    {
    return width;
    }
    int DropShadow::getHeight()
    {
    return height;
    }
    void DropShadow::setCustomWidth(int value)
    {
    width = value;
    qDebug()<<"DropShadow::setCustomWidth("<<value<<")";
    }
    void DropShadow::setCustomHeight(int value)
    {
    height = value;
    qDebug()<<"DropShadow::setCustomHeight("<<value<<")";
    }
    QColor DropShadow::getColor() const
    {
    return m_color;
    }
    void DropShadow::setColor(const QColor &color)
    {
    m_color = color;
    }
    double DropShadow::getBlurRadius() const
    {
    return radius;
    }
    double DropShadow::getXOffset() const
    {
    return horizontalOffset;
    }
    double DropShadow::getYOffset() const
    {
    return verticalOffset;
    }
    void DropShadow::setXOffset(double value)
    {
    horizontalOffset = value;
    }
    void DropShadow::setYOffset(double value)
    {
    verticalOffset = value;
    }
    void DropShadow::setBlurRadius(const double blurRadius)
    {
    radius = blurRadius;
    }
    void DropShadow::setImageSource(QString image)
    {
    sourceImage = image;
    sgnSourceImageChanged();
    }
    QString DropShadow::getImageSource() const
    {
    return sourceImage;
    }
    void DropShadow::sltOnsourceChanged()
    {
    myImage->load(sourceImage);
    if(width == 0)
    {
    width = myImage->width();
    }
    if(height == 0)
    {
    height = myImage->height();
    }
    this->setWidth(width);
    this->setHeight(height);
    pixmap = QPixmap::fromImage( myImage->scaled(width,height,Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
    }
    void DropShadow::paint(QPainter *painter)
    {
    view.setScene(scene);
    scene->setSceneRect(QRect(0,0,800,480));
    pShadow->setColor(QColor(m_color));
    pShadow->setBlurRadius(radius);
    pShadow->setXOffset(horizontalOffset);
    pShadow->setYOffset(verticalOffset);
    QGraphicsPixmapItem *p = view.scene()->addPixmap(pixmap);
    p->setGraphicsEffect(pShadow);
    view.render(painter,QRect(0,0,800,480),QRect(0,0,800,480));
    }
    DropShadow::~DropShadow()
    {
    delete myImage;
    delete pShadow;
    delete scene;
    }
    @

    [edit: added missing coding tags @ SGaist]



  • this is a link to my project , hope it could help you :
    https://github.com/alhajjar/QmlEffects



  • this is a link to my project , hope it could help you :
    https://github.com/alhajjar/QmlEffects


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.