Modifying Images

  • Hello everyone,
    I've read many articles about differences between QImage and QPixmap. I can easly use QGraphicsPixmapItem to display an image from disk. However, if I want to modify pixels of this image in runtime, I'm forced to convert that pixmap to QImage, modify it, convert back to pixmap and display. This is how it looks so far:

    if(type == InterfaceType::HPBAR || type == InterfaceType::MPBAR)
            QImage image;
            if(type == InterfaceType::HPBAR)
            int length = image.width();
            length = (int)(((double)length * (double)value) / 100.0);
            for(int i = 0; i< image.width(); i++)
                for(int j = 0; j< image.height(); j++)
                    QColor color(image.pixel(i,j));
            QPixmap pix = QPixmap::fromImage(image);

    This piece of code changes Image (which is Health Bar or Mana Bar) to show percentage value of those attributes. For example, if there's 50% health points left, 50% of this image is half-transparent. The object itself inherits from QGraphicsPixmapItem. I know it's not the best way to do things like this, because converting Image to Pixmap is expensive operation.
    Is there something different, that allows me display images and modify them anytime I want?

    Best regards.

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    What about putting an overlay on top of your bar rather than modify it every time ?

    Just draw your image and put another QGraphicsItem on top of it that you paint to the right value.

  • Thank you for your reply.

    I guess I dont understand. What kind of overlay? Like drawing half-transparent image to cover bar?

  • Lifetime Qt Champion

    Yes, that was the idea. But I'm realising I may have misunderstood your needs.

    In fact, you want that the complete bar changes, not some kind of gauge overlay, right ?

  • This is how it looks so far:

    alt text

    I'd like to do it this way, I think it's more apparent than gauge, isn't it?

  • Moderators

    I think @SGaist has the right idea. You can use one (semi-transparent) image as the base and then just paint over it (or rather have an opaque item on top). Also you could load the images directly, instead of loading them as pixmaps and then converting to QImage.

  • Okay, so leave the Pixmap as it is and use QPainter to make another half-transparent pixmap and cover the main one? Seems to be a good idea :D

  • Moderators

    @Axator said in Modifying Images:

    Okay, so leave the Pixmap as it is and use QPainter to make another half-transparent pixmap and cover the main one?

    Actually I'd go about it the other way around - put the transparent one (and blend it, possibly reducing the number of compositions you need to do). And then just pain the opaque one on top. One thing you should consider, however, is that all this (i.e. the composition modes) are done through the CPU, so you might not get the computational power you need if you intend to have dynamic content behind the semi-transparent items.

  • What do you think about this?

    int length = this->boundingRect().width();
            length = (int)(((double)length * (double)value) / 100.0);
            QPixmap pix(this->boundingRect().width() - length, this->boundingRect().height());
            QPainter p;
            p.fillRect(pix.rect(), QColor(0, 0, 0, 120));
            gauge->setPos(pos().x()+length, pos().y());

    It works fine and the effect is the same as on example pixtures above.