Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Работа с гиф анимацией
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Система рисования. Печать
igor_bogomolov
Привет всем.
Недавно задался вопросом, как можно средствами Qt вытащить кадр из gif.
Оказалось, что для этого существует класс QImageReader.
Для работы с графическими файлами поддерживающих анимацию, есть методы, которые позволяют нам узнать, сколько кадров содержит файл, период обновления кадров, возможно ли перейти на кадр с определенным номером, и т.д.

Но, при работе с этими методами возникли некоторые "трудности".
методы
Цитата
int QImageReader::loopCount () const
int QImageReader::imageCount () const
всегда возвращают ноль, т.е. мы не можем узнать, сколько реально кадров содержит файл.

Цитата
bool QImageReader::jumpToImage ( int imageNumber )
bool QImageReader::jumpToNextImage ()
всегда возвращают false, и мы не знаем, можем ли мы считывать следующий кадр или нет. Усложняемся все тем, что если мы производим лишнюю операцию чтения, возникает непонятная для меня ошибка, и даже если мы снова сделаем setFileName, считать мы больше ничего не сможем. Т.е. новый цикл анимации не начнем.

Собственно говоря, у меня вопрос к сообществу. Что это бага, или я не разобрался в вопросе?


------------------------------------------------------------------------------------------------------------

Тем не менее, если вручную контролировать количество кадров (можно узнать любым графическим редактором), работа с гиф анимацией становится простой и удобной. Предлагаю, на мой взгляд, очень интересную демку. Надеюсь Вам понравится :).
Компилируем, смотрим, отписываемся о результатах.
kwisp
Цитата(igor_bogomolov @ 29.5.2009, 14:32) *
int QImageReader::loopCount () const

вернуло 999 для кота(кошки).
Цитата
canRead() is a lightweight function that only does a quick test to see if the image data is valid. read() may still return false after canRead() returns true, if the image data is corrupt.
igor_bogomolov
Цитата(kwisp @ 29.5.2009, 15:07) *
вернуло 999 для кота(кошки).
А реально там 11 кодров. nextImageDelay и loopCount возвращают чуш.

Надо попробовать заменить QImageReader на QMovie. Он такой же набор методов предоставляет.

kwisp, спасибо разобрался. Счетчик действительно лишний. А как новый цикл начать без использования setFileName?
kwisp
igor_bogomolov,
лажа какая то
в исходниках добрался до виртуальной функции класса QImageIOHandler::imageCount() int
int QImageIOHandler::imageCount() const
{
    return canRead() ? 1 : 0;
}
int QImageReader::imageCount() const
{
    if (!d->initHandler())
        return -1;
    return d->handler->imageCount();
}

собственно всё.
она кроме 0 и 1 ничего не вернет
:)

Цитата(kwisp @ 29.5.2009, 15:07) *
canRead() is a lightweight function that only does a quick test to see if the image data is valid. read() may still return false after canRead() returns true, if the image data is corrupt.

я это ктому что после рида то проверка нужна :) у тебя нет

Цитата(igor_bogomolov @ 29.5.2009, 15:44) *
А как новый цикл начать без использования setFileName?

походу только так
bool QImageReader::jumpToImage ( int imageNumber )
igor_bogomolov
Цитата(kwisp @ 29.5.2009, 15:49) *
я это ктому что после рида то проверка нужна у тебя нет
Переделат так. Все работает. За количеством кадров следить не надо.

Раскрывающийся текст
    if(imageR.canRead()) {
        image = imageR.read();
        if(mirror) image = image.mirrored(true,false);
        pix = QPixmap::fromImage(image);
        setPixmap(pix);
        setMask(pix.mask());
    } else {
        //imageR.jumpToImage(1);
        imageR.setFileName("../persian.gif");
    }


Цитата(kwisp @ 29.5.2009, 15:49) *
походу только так
bool QImageReader::jumpToImage ( int imageNumber )
Не получается этим методом (((
Litkevich Yuriy
Я для проигрования gif'ки использовал QMovie + QLable.
kwisp
igor_bogomolov,
загляни в исходники. очень удивишься.
класс QImageIOHandler содержит виртуальные функции и предназначен походу для наследования и переопределения их. из файла
qimgeiohandler.cpp
Раскрывающийся текст

int QImageIOHandler::imageCount() const
{
    return canRead() ? 1 : 0;
}

/*!
   For image formats that support animation, this function jumps to the
   next image.

   The default implementation does nothing, and returns false.
*/
bool QImageIOHandler::jumpToNextImage()
{
    return false;
}

/*!
   For image formats that support animation, this function jumps to the image
   whose sequence number is \a imageNumber. The next call to read() will
   attempt to read this image.

   The default implementation does nothing, and returns false.
*/
bool QImageIOHandler::jumpToImage(int imageNumber)
{
    Q_UNUSED(imageNumber);
    return false;
}

/*!
    For image formats that support animation, this function returns
    the number of times the animation should loop. If the image format
    does not support animation, 0 is returned.
*/
int QImageIOHandler::loopCount() const
{
    return 0;
}

/*!
    For image formats that support animation, this function returns
    the number of milliseconds to wait until reading the next
    image. If the image format does not support animation, 0 is
    returned.
*/
int QImageIOHandler::nextImageDelay() const
{
    return 0;
}


не могу найти в исходниках где
переопределяется переопределяются данные виртуальные функции :(
igor_bogomolov
Цитата(Litkevich Yuriy @ 29.5.2009, 15:58) *
Я для проигрования gif'ки использовал QMovie + QLable.
Это понятно. Все так используют. А если нужен overpainting? ;)
QLabel тут не подойтет. QMovie конечно можно использовать вместо QImageReader. Наверное так и надо сделать.

Собери примет из первого сообщения. Помоему прикольно.
Litkevich Yuriy
Цитата(igor_bogomolov @ 29.5.2009, 19:06) *
Собери примет из первого сообщения.
Эх последнее время у меня ни на что времени не хватает :(
kwisp
нашел где переопределяют imageCount
похоже либо бага либо недоделка либо я накосячил.

int QGifHandler::imageCount() const
{
    return 0; // Don't know
}

таж фигня вид сбоку и функция не виртуальная.

мда.... сразу мона было позырить
сюда

там вообще не только одна функция непереопределена штук 5 недоделаны.
Litkevich Yuriy
Цитата(kwisp @ 29.5.2009, 19:41) *
мда.... сразу мона было позырить
походу надо запостить в трекер более явно, что мол реализация отсутствует.
Т.к. запланировано на 4.1, может уже забыли.
igor_bogomolov
kwisp, я переделал все на QMovie. Тож же самый функционал, потяжеловеснее только. Хотелось бы QImageReader обойтись. Да ну и черт с ним.

У QMovie loopCount () & frameCount () возвращают -1. Зато работает jumpToFrame и nextFrameDelaу.

Цитата(kwisp)
мда.... сразу мона было позырить сюда
Бага то старинная и приоритет высокий. Странно что до сих пор не пофиксили.
kwisp
я бы сказал для гифа точно в классе
QGifHandler не перепопределены толком виртуальные функции предка QImageIOHandler
в остальных лень смотреть кому интересно в src/plugins/imageformats/ лежат дочерние классы в src\gui\image\ родитель QImageIOHandler

Цитата(igor_bogomolov @ 29.5.2009, 16:58) *
У QMovie loopCount () & frameCount () возвращают -1

странно в исходниках они вроде переопределены по своему .... хм..
ну да черт с ними точно. потому что посмотрел я на баги.... многовато их... надо почаще туда лазить а то так голову поломать можно.

P.S. кошара зачётная.
почитай там в юморе в непридуманных историях есть про кота как раз рассказик.
Rocky
Ребят а с тех пор никто с гифками не работал? У меня щас 4.6.1.... а по ходу все тоже самое.. ( Как можно остановить анимацию когда последний кадр? я делал через QMovie... Походу сигнал finished не генерируется... А гифка так вечно и проигрывается, а нужно чтоб она один раз проиграла, и все... Блин(
kwisp
не делал.
посмотри баги может они так и остались.
SABROG
Узнай количество фреймов:

int QMovie::frameCount () const

и лови сигнал:

void QMovie::frameChanged ( int frameNumber ) [signal]

В слоте проверяй если frameNumber == frameCount(), то вызывай stop():

QTimer::singleShot(0, movie, SLOT(stop());

Чтобы movie успел проиграть последний фрейм и только после этого остановился. А finished() наверно никогда не придет, если в gif'ке стоит свойство играть по кругу.

Если даже frameCount() не будет работать, то максимальное количество фреймов всегда можно обновить в слоте на frameChanged() и если новое значение меньше старого, значит пошел второй круг.
Rocky
SABROG, я так пробовал... frameCount всегда возвращает 0. в слоте, соединенном с сигналом frameChanged параметр frameNumber всегда 0. Более того, если этот сигнал соединять, то вообще срывает стэк почемуто =)

Боюсь что поддержки гифоф так и нет... Ладно, напишу свой класс, которому буду просто кормить последовательность картинок...
SABROG
Выложи проект, посмотрю.
Rocky
SABROG, спасибо но там точно баги. Я гуглил. Чтобы не тратить время просто свой класс написал на основе QLabel которому последовательность картинок передаю..
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.