1

I have been playing with QMovie a bit trying to mirror a movie as well as play it in reverse. For the mirroring bit I tried assigning a negative width to no avail. Since QImage does offer facilities for this I had hoped QMovie would do the same. There don't seem to be any facilities in the QMovie object for those things, so I'm wondering if I could manipulate the QIODevice to the QMovie object instead to achieve this, but this is completely new territory for me and I don't see anything obvious in the documentation that would achieve mirroring or playing in reverse. The code example to start with would be the same as on the PySide page:

label = QLabel()
movie = QMovie("animations/fire.gif")
label.setMovie(movie)
movie.start()

Any ideas would be greatly appreciated.

Thanks, Frank

Frank Rueter
  • 729
  • 1
  • 10
  • 21

1 Answers1

2

QMovie doesn't provide the methods to set the current image, so you have to use directly QImageReader to play it in reverse (using QImageReader::jumpToImage()). This is not very easy bacause the delay between a frame and the next can change, but however you can get it calling QImageReader::nextImageDelay().

To display the movie, you can implement your own widget to draw the movie as you want.

In the paintEvent() you can set a transformation to the painter to get the mirror effect and than draw the current image of the movie.

Example:

void MyWidget::paintEvent(QPaintEvent * event)
{
    QPainter painter(this);
    painter.scale(-1, 1); // x-axis mirror
    //here maybe you must adjust the transformation to center and scale the movie.
    painter.drawImage(0, 0, currentImage);
}

To play the movie you have to set a timer that change the current image.

Example:

//you must create a timer in the constructor and connect it to this slot
void MyWidget::timeoutSlot()
{
    int currentImageIndex;
    //here you have to compute the image index
    imageReader.jumpToImage(currentImageIndex);
    currentImage = imageReader.read(); //maybe you want to read it only if the index is changed
    update();
}

Here you can find an example of widget subclass, with timer and painter transformation

See also QImageReader, QTimer, QWidget::paintEvent

Fabio
  • 2,522
  • 1
  • 15
  • 25
  • Thanks, that sounds like I need to re-implement QMovie altogether, shame. I will try your suggestions and see how far I get, thanks. – Frank Rueter Jul 13 '16 at 05:57
  • so I tried your suggestion and wrote my own widget using QImageReader. As a first test I hooked it up to a QSlider to drive the current frame of the animated gif, but whatever number I feed **QImageReader.jumpToImage**, subsequent calls to **read()** only ever read the next frame until the end is reached. So I can't control what frame to read at all at the moment – Frank Rueter Jul 13 '16 at 07:23
  • Sorry, it seems that the implementation of jumpToImage for GIF doesn't work. Maybe you can load and cache all the frames in a map and take the images from it in the timer slot (this can cause a large memory usage) – Fabio Jul 13 '16 at 08:11
  • Ha, funny, I just tried exactly that a minute before reading your reply. I needed to use cacheAll() on QMovie anyway to be able to scrub back and forth without delay, which is an important feature, so I just wrote a simple loop that repeatedly reads the image reader and stores the resulting QImages in a list. I'm sure this will make my memory consumption go through the roof eventually, but that might just be the price for what I'm after. I just need to write equivalent methods to mimic all the other QMovie features I need now and hope that memory management doesn't become imposisble. – Frank Rueter Jul 13 '16 at 21:17
  • I will mark this as the answer. While it's not as straight forward as I had hoped, Fabio's suggestion certainly pointed me in the right direction. Thanks Fabio. – Frank Rueter Jul 14 '16 at 01:29