How to show QImage from http url?



  • Hey, I would like to cache images from an url and show them from local file system, but if file doesn't exists then I would need to download it from url. Any advices how I should proceed?

    I found this class:
    QDeclarativeImageProvider, where I can return Image from Qt side and there I can do something like this:

    @QImage requestImage(const QString &id;, QSize *size, const QSize &requestedSize;)
    {

         QDir dir;
         QFile file( dir.absolutePath() + "images/" + id + ".jpg" );
    
         if (file.exists())
         {
            QImage img;
            img.load(dir.absolutePath() + "images/" + id + ".jpg");
            return img; 
         }
         else {
    
            Load from url
    
         }
    

    }@

    How to do that load from url part.

    I found this example: http://www.qtcentre.org/threads/1483-Qt4-How-to-load-Url-image-into-QImage
    But how can I return the image, when it's created in slot?

    Thanks for any tips.



  • You can also use custom "QDeclarativeNetworkAccessManagerFactory":http://doc.qt.nokia.com/4.7/qdeclarativenetworkaccessmanagerfactory.html to cache images with cache-enabled QNAM.



  • [quote author="Denis Kormalev" date="1311023033"]You can also use custom "QDeclarativeNetworkAccessManagerFactory":http://doc.qt.nokia.com/4.7/qdeclarativenetworkaccessmanagerfactory.html to cache images with cache-enabled QNAM.[/quote]

    That sounds even trickier task



  • Hi jkosonen, you want to show your images with QML?



  • [quote author="Chuck Gao" date="1311058507"]Hi jkosonen, you want to show your images with QML?[/quote]

    Yes :)



  • If so, i think the key point is the file path(local or internet). QML Image element's source can be a url, so you just need to get the file path. The element itself will take care of the http part.



  • [quote author="Chuck Gao" date="1311063146"]If so, i think the key point is the file path(local or internet). QML Image element's source can be a url, so you just need to get the file path. The element itself will take care of the http part.[/quote]

    Yes, I know. but I don't want to download it from the internet everytime, but make a local copy and then take it from there if exists.



  • You want cache the images yourself ? I mean, store them into the cache and get them from the cache. I'm not sure if the QML Image element use caching when load url image. But you can try QNetworkDiskCache. I found this in the document: "Images are cached and shared internally, so if several Image elements have the same source, only one copy of the image will be loaded". Let's look into the source code. :-)



  • Yes, I would like to cache by myself :) I don't think that the QML caches those automatically since it always takes so long to get the images to the screen.

    Maybe need to investigate that QNetworkDiscCache, but I wouldn't mind if someone could give me a solution to problem I had in the main question :)



  • I have a look at the source code, and QML will cache those images for you, with
    @
    QDeclarativeImageBase::load()
    {
    ...
    QDeclarativePixmap::load(QDeclarativeEngine *engine, const QUrl &url;, const QSize &requestSize;, bool async)
    {
    if (d) { d->release(); d = 0; }

    QDeclarativePixmapKey key = { &url;, &requestSize; };
    QDeclarativePixmapStore *store = pixmapStore();
    
    QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::Iterator iter = store->m_cache.find(key);
    
    if (iter == store->m_cache.end()) {
        if (async) {
            // pixmaps can only be loaded synchronously
            if (url.scheme() == QLatin1String("image") 
                    && QDeclarativeEnginePrivate::get(engine)->getImageProviderType(url) == QDeclarativeImageProvider::Pixmap) {
                async = false;
            }
        }
    
        if (!async) {
            bool ok = false;
            d = createPixmapDataSync(engine, url, requestSize, &ok;);
            if (ok) {
                d->addToCache();
                return;
            }
            if (d)  // loadable, but encountered error while loading
                return;
        } 
    
        if (!engine)
            return;
    
        QDeclarativePixmapReader *reader = QDeclarativePixmapReader::instance(engine);
    
        d = new QDeclarativePixmapData(url, requestSize);
        d->addToCache();
    
        d->reply = reader->getImage(d);
    } else {
        d = *iter;
        d->addref();
    }
    

    }

    .....
    }
    @



  • Then it takes awful lot of time to show the image if it already comes from cache...



  • [quote author="jkosonen" date="1311064731"]Yes, I would like to cache by myself :) I don't think that the QML caches those automatically since it always takes so long to get the images to the screen.

    Maybe need to investigate that QNetworkDiscCache, but I wouldn't mind if someone could give me a solution to problem I had in the main question :)[/quote]

    QNetworkDiskCache is the same way I've suggested. It is really not hard (maybe a 5 or 10 lines of code)



  • [quote author="Denis Kormalev" date="1311065955"][quote author="jkosonen" date="1311064731"]Yes, I would like to cache by myself :) I don't think that the QML caches those automatically since it always takes so long to get the images to the screen.

    Maybe need to investigate that QNetworkDiscCache, but I wouldn't mind if someone could give me a solution to problem I had in the main question :)[/quote]

    QNetworkDiskCache is the same way I've suggested. It is really not hard (maybe a 5 or 10 lines of code)[/quote]

    Can you point me to any site with example, with QML?



  • "example about QDeclarativeNetworkAccessManagerFactory":http://doc.qt.nokia.com/4.7/declarative-cppextensions-networkaccessmanagerfactory.html
    "QNetworkDiskCache":http://doc.qt.nokia.com/4.7/qnetworkdiskcache.html (there is an example of how to use it with QNAM)



  • [quote author="Denis Kormalev" date="1311066630"]"example about QDeclarativeNetworkAccessManagerFactory":http://doc.qt.nokia.com/4.7/declarative-cppextensions-networkaccessmanagerfactory.html
    "QNetworkDiskCache":http://doc.qt.nokia.com/4.7/qnetworkdiskcache.html (there is an example of how to use it with QNAM)[/quote]

    Thanks, will try that!

    but there is this:

    When sending requests, to control the preference of when to use the cache and when to use the network, consider the following:

    @ // do a normal request (preferred from network, as this is the default)
    QNetworkRequest request(QUrl(QString("http://qt.nokia.com")));
    manager->get(request);

    // do a request preferred from cache
    QNetworkRequest request2(QUrl(QString("http://qt.nokia.com")));
    request2.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
    manager->get(request2);@

    How do I say in QML to prfer cache?



  • jkosonen, it will prefer a cache in most part of cases (if we are talking about images)



  • [quote author="Denis Kormalev" date="1311067186"]jkosonen, it will prefer a cache in most part of cases (if we are talking about images)[/quote]

    OK, but how to say then not to use cache, or clear cache?
    Cache isn't always preferred, would be nice to know when it is used and when it's not.



  • jkosonen, clearing cache is possbile with simple removing all contents of cache dir. I'm not aware of any other ways.



  • You can try Qt 4.8, it has a better image caching for QML. Hope it will work for you :D



  • Can anyone help with the question in the first post, how that could be done?



  • [quote author="jkosonen" date="1312700928"]Can anyone help with the question in the first post, how that could be done?[/quote]

    By using [[Doc:QNetworkAccessManager]] - there are numerous examples out there (even in this forums :-) ) that show you the basic path.



  • Don't think so that there is... and what a useless post..

    [quote author="Volker" date="1312717450"]
    [quote author="jkosonen" date="1312700928"]Can anyone help with the question in the first post, how that could be done?[/quote]

    By using [[Doc:QNetworkAccessManager]] - there are numerous examples out there (even in this forums :-) ) that show you the basic path.[/quote]



  • So another useless post with another "link":http://developer.qt.nokia.com/wiki/Download_Data_from_URL, maybe of help this time.

    I'm so awfully sorry to have put you on the wrong track. Of course it's not in the forums, but in the wiki. Silly me.



  • [quote author="Volker" date="1312729123"]So another useless post with another "link":http://developer.qt.nokia.com/wiki/Download_Data_from_URL, maybe of help this time.

    I'm so awfully sorry to have put you on the wrong track. Of course it's not in the forums, but in the wiki. Silly me.[/quote]

    That still doesn't really help in the original guestion, how I can return the Image trough slot..



  • I don't get your question.

    This does not work?

    @
    QImage img;
    // fill the image with data
    return img;
    @



  • [quote author="Volker" date="1312731557"]I don't get your question.

    This does not work?

    @
    QImage img;
    // fill the image with data
    return img;
    @

    [/quote]

    @

    QImage requestImage(const QString &id;, QSize *size, const QSize &requestedSize;)
    {

         QDir dir;
         QFile file&#40; dir.absolutePath(&#41; + "images/" + id + ".jpg" );
    
         if (file.exists())
         {
            QImage img;
            img.load(dir.absolutePath() + "images/" + id + ".jpg");
            return img;
         }
         else {
    
            Load from url
    
         }
    

    }
    @

    Don't know how I can fill the image inside the else slot. Maybe I just don't understand something.



  • Download the image, e.g. by using the QNetworkAccessManager download example mentioned in the wiki. You may want to extend it to pass the desired path of the file. The helper class saves the downloaded file to a file, then just continue like it's already there. I would change the logic a bit:

    @

    QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize)
    {
    QDir dir;
        QFileInfo fi( dir.absolutePath() + "images/" + id + ".jpg" );
    if(!fi.exists()) {
    // download the image
    // using the helper class
    // it saves the image to the path
    // denoted by file
    // pass the file path with
    // fi.absoluteFilePath()
    }
    return QImage(fi.absoluteFilePath());
    }
    @

    The code is the same once you actually have the image data. So just check if it's there, download it if not. After that it is "in the cache".

    Oh, and of course, in the download helper or the if part, make sure you actually got an image from the server and check for HTTP in the download helper. The server may be down or there might be another error on the network part - people are pulling plugs from time to time :-)

    EDIT:
    there was some copy'n'paste garbage in the code, so make sure to copy it from the forums, not the notification email.


Log in to reply
 

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