Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: BagmutA от Апрель 20, 2011, 11:19



Название: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 11:19
Созаю миниатюры изображений:
Код
C++ (Qt)
QImage im;
im.load(filename);
im = im.scaled(icoWidth, icoHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
im.save( filename_s, "JPG", 95);
Самый медленый этап: im.load(filename); -- занимает 80-90% процетов времени на создание миниатюр.
В общей сложности получается раза в 2-3 медленее чем это происходит в любом просмотрщике изображений(например Gwenview).
Подскажите, пожалуйста, как можно ускорить этот процесс, как создавать миниатюры не загружая полностью изображение.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Fat-Zer от Апрель 20, 2011, 11:29
а почему бы не посмотреть, как это сделано в gwenview?


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: meego_man от Апрель 20, 2011, 11:39
Созаю миниатюры изображений:
Код
C++ (Qt)
QImage im;
im.load(filename);
im = im.scaled(icoWidth, icoHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);
im.save( filename_s, "JPG", 95);
Самый медленый этап: im.load(filename); -- занимает 80-90% процетов времени на создание миниатюр.
В общей сложности получается раза в 2-3 медленее чем это происходит в любом просмотрщике изображений(например Gwenview).
Подскажите, пожалуйста, как можно ускорить этот процесс, как создавать миниатюры не загружая полностью изображение.
у JPG есть вариант быстрой загрузки изображения. Правда Qt вроде как его не использует. Помню мне тоже требовалось быстро создавать миниатюры изображений, для этого я использовал FreeImage библиотеку. В ней есть вариант выбора скорость/качество.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Fat-Zer от Апрель 20, 2011, 11:46
если кратко про gwenview, то они загружают изображения в отдельных потоках с помощью QtConcurrent


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 12:19
если кратко про gwenview, то они загружают изображения в отдельных потоках с помощью QtConcurrent
Я собственно это делаю в QThread. А вот как быстро загружать изображение ???


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 15:21
Есть идея использовать QIcon:
Код
C++ (Qt)
QImage im;
QIcon ico;
QSize size(200, 200);
ico.addFile(MainWindow::currentDir + MainWindow::listImage.at(i), size);
im = ico.pixmap(size).toImage();
im.save( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i), "JPG", 95);
Но проблема в том, что в QThread небезопасно использовать QPixmap, пишет:QPixmap: It is not safe to use pixmaps outside the GUI thread. И соответственно не сохраняется миниатюра.
Как можно преобразовать QIcon непосредственно в QImage или хотя бы без промежуточного использования QPixmap?


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Igors от Апрель 20, 2011, 15:27
Я собственно это делаю в QThread. А вот как быстро загружать изображение ???
кэшировать (по фолдеру)


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 15:36
Я собственно это делаю в QThread. А вот как быстро загружать изображение ???
кэшировать (по фолдеру)
Кэширование будет полезно если я буду использовать одну и ту же картинку много раз, но я ее использую только раз.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Fat-Zer от Апрель 20, 2011, 15:43
Я собственно это делаю в QThread. А вот как быстро загружать изображение ???
если это и так, то из вашего кода этого не видно...

ЗЫ: именно im.load() исполнять в отдельном потоке.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 15:52
Я собственно это делаю в QThread. А вот как быстро загружать изображение ???
если это и так, то из вашего кода этого не видно...

ЗЫ: именно im.load() исполнять в отдельном потоке.

Ну собственно мой класс унаследованій от QThread:
Код
C++ (Qt)
class MyThread : public QThread
{
public:
   MyThread()
   {
   }
 
   void run()
   {
    QDir curDir;
    curDir.setPath(MainWindow::currentDir);
    if ( !curDir.exists(".prev/") &&  MainWindow::listImage_Cout > 0 )
    {
    curDir.mkdir(".prev/");
    }
 
#ifdef WINDOWS
    QString path(MainWindow::currentDir + ".prev/");
    std::wstring wpath = path.toStdWString();
    const wchar_t * temp= wpath.c_str();
SetFileAttributes(temp,FILE_ATTRIBUTE_HIDDEN);
#endif
    for (int i=0; (i<MainWindow::listImage_Cout) && !MainWindow::stop_thread; ++i)
    {
    if (!QFile::exists( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i) ))
    {
    QImage im;
QIcon ico;
QSize size(200, 200);
ico.addFile(MainWindow::currentDir + MainWindow::listImage.at(i), size);
im = ico.pixmap(size).toImage();
im.save( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i), "JPG", 95);
 
    }
    }
   }
 
};


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Igors от Апрель 20, 2011, 16:00
Кэширование будет полезно если я буду использовать одну и ту же картинку много раз, но я ее использую только раз.
Зато используете много картинок которые (весьма вероятно) из одного фолдера. Ну и грузите их "пока трамваи ходют"


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 16:22
Кэширование будет полезно если я буду использовать одну и ту же картинку много раз, но я ее использую только раз.
Зато используете много картинок которые (весьма вероятно) из одного фолдера. Ну и грузите их "пока трамваи ходют"
Будут непрерывно создаватся миниатюры одна за другой, а так как на открытие картинки(загрузки в кеш) уходит 80-90% времени, то пользы от кэша практически не будет


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Fat-Zer от Апрель 20, 2011, 16:38
Ну собственно мой класс унаследованій от QThread:
Код
C++ (Qt)
class MyThread : public QThread
{
public:
   MyThread()
   {
   }
 
   void run()
   {
    QDir curDir;
    curDir.setPath(MainWindow::currentDir);
    if ( !curDir.exists(".prev/") &&  MainWindow::listImage_Cout > 0 )
    {
    curDir.mkdir(".prev/");
    }
 
#ifdef WINDOWS
    QString path(MainWindow::currentDir + ".prev/");
    std::wstring wpath = path.toStdWString();
    const wchar_t * temp= wpath.c_str();
SetFileAttributes(temp,FILE_ATTRIBUTE_HIDDEN);
#endif
    for (int i=0; (i<MainWindow::listImage_Cout) && !MainWindow::stop_thread; ++i)
    {
    if (!QFile::exists( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i) ))
    {
    QImage im;
QIcon ico;
QSize size(200, 200);
ico.addFile(MainWindow::currentDir + MainWindow::listImage.at(i), size);
im = ico.pixmap(size).toImage();
im.save( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i), "JPG", 95);
 
    }
    }
   }
 
};
не то... я про первый способ. именно загружать изображение в отдельном потоке. а то и в нескольких.

QIcon загружает файл на im = ico.pixmap(size).toImage(); и тут мы никаких преимуществ не получаем.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 16:45
Ну собственно мой класс унаследованій от QThread:
Код
C++ (Qt)
class MyThread : public QThread
{
public:
   MyThread()
   {
   }
 
   void run()
   {
    QDir curDir;
    curDir.setPath(MainWindow::currentDir);
    if ( !curDir.exists(".prev/") &&  MainWindow::listImage_Cout > 0 )
    {
    curDir.mkdir(".prev/");
    }
 
#ifdef WINDOWS
    QString path(MainWindow::currentDir + ".prev/");
    std::wstring wpath = path.toStdWString();
    const wchar_t * temp= wpath.c_str();
SetFileAttributes(temp,FILE_ATTRIBUTE_HIDDEN);
#endif
    for (int i=0; (i<MainWindow::listImage_Cout) && !MainWindow::stop_thread; ++i)
    {
    if (!QFile::exists( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i) ))
    {
    QImage im;
QIcon ico;
QSize size(200, 200);
ico.addFile(MainWindow::currentDir + MainWindow::listImage.at(i), size);
im = ico.pixmap(size).toImage();
im.save( MainWindow::currentDir + ".prev/" + MainWindow::listName.at(i), "JPG", 95);
 
    }
    }
   }
 
};
не то... я про первый способ. именно загружать изображение в отдельном потоке. а то и в нескольких.

QIcon загружает файл на im = ico.pixmap(size).toImage(); и тут мы никаких преимуществ не получаем.

Так QIcon уже уменьшен до размера 200х200.


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: Fat-Zer от Апрель 20, 2011, 16:49
Так QIcon уже уменьшен до размера 200х200.
так вы же сами сказали, что 80% времени тратится на загрузку файла. причём тут уменьшение?


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 20, 2011, 17:07
Так QIcon уже уменьшен до размера 200х200.
так вы же сами сказали, что 80% времени тратится на загрузку файла. причём тут уменьшение?

Есть предположение что в QIcon оптимизировано создание миниатюр(я это проверял без сохранения иконки), а вот собствено чтобы проверить действительно ли это так надо организовать сохранение QIcon реализованое в моем потоке QThread. :-\


Название: Re: Как быстро создавать миниатюры изображений
Отправлено: BagmutA от Апрель 23, 2011, 11:09
Проблема решена.
Может кому то пригодится:
Код
C++ (Qt)
int icoWidth = 200;
int icoHeight = 200;
   QImageReader imageReader(MainWindow::currentDir + MainWindow::listImage.at(i));
 
   QSize size;
   int image_width;
   int image_height;
 
   if (imageReader.supportsOption(QImageIOHandler::Size))
   {
       size = imageReader.size();
       image_width = size.width();
       image_height = size.height();
   }
 
   double ratio = (double)image_width / (double)image_height;
   if (ratio >= 1)
   {
image_width = icoWidth;
image_height = image_width / ratio;
   }
   else
   {
    image_height = icoHeight;
    image_width = image_height * ratio;
   }
 
   imageReader.setScaledSize(QSize(image_width, image_height));
   QImage image = imageReader.read();