Can load remote images and cache them locally.

This commit is contained in:
2018-12-18 18:31:51 +01:00
parent 6e7645f17b
commit 0148f7aaa5
11 changed files with 379 additions and 3 deletions

163
helpers/imageloadhelper.cpp Normal file
View File

@ -0,0 +1,163 @@
#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QCryptographicHash>
#include <QMap>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QImage>
#include <QImageReader>
#include <QPixmap>
#include <QLabel>
#include "imageloadhelper.h"
#include "../config.h"
#include "../utils/filesutils.h"
//This header should be called only from this file
// (QObject subclass seems not to be declarable in CPP files)
#include "../data/qlabelholder.h"
/**
* The list of pending labels for an image
*/
static QMap<QString, QList<QLabelHolder*>> privateList;
/**
* Network Access Manager used to download images
*/
static QNetworkAccessManager accessManager;
/**
* The first and the last instance of this object
*/
static ImageLoadHelper *mHelper = nullptr;
ImageLoadHelper::ImageLoadHelper(QObject *parent) : QObject(parent)
{
//Nothing yet
}
void ImageLoadHelper::Load(QLabel *label, const QString &url)
{
//Construct object if required
if(mHelper == nullptr)
mHelper = new ImageLoadHelper();
//Check if the image has already been downloaded
if(IsDownloaded(url)){
ApplyImage(label, url);
return;
}
//Check if download is already running
if(privateList.contains(url)){
QList<QLabelHolder *> swapList = privateList.take(url);
swapList.append(new QLabelHolder(label));
privateList.insert(url, swapList);
return;
}
//If we get there, we have to launch the download of the image
QList<QLabelHolder *> list;
list.append(new QLabelHolder(label));
privateList.insert(url, list);
Download(url);
}
void ImageLoadHelper::NetworkError()
{
qWarning("Image Load Helper error : Network error while connecting to server!");
}
void ImageLoadHelper::NetworkRequestFinished()
{
//If the request is a success, we can save the image, else we can not do anything
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
reply->deleteLater();
if(reply->error() != QNetworkReply::NoError){
qWarning("Can not process image because we encountered an error while downloading it!");
return;
}
//Save the image
QString url = reply->url().toString();
QImageReader reader(reply);
QImage image = reader.read();
//Check if the image could not be decode
if(image.isNull()){
qWarning("Downloaded image from %s is not valid!", url.toStdString().c_str());
return;
}
//Save the image
QString file_path = GetImageStoragePath(url);
if(!image.save(file_path, "PNG")){
qWarning("Could not save image from %s to %s !", url.toStdString().c_str(), file_path.toStdString().c_str());
return;
}
//Process the list of awaiting labels
QPixmap pixmap = QPixmap::fromImage(image);
QList<QLabelHolder *> labels = privateList.take(url);
for(QLabelHolder *currLabel : labels)
if(currLabel->label() != nullptr)
ApplyImage(currLabel->label(), pixmap);
}
void ImageLoadHelper::SSLErrors()
{
qWarning("Image Load Helper error : SSL error while connecting to server!");
}
void ImageLoadHelper::Download(const QString &url)
{
qWarning("Download image located at URL: %s", url.toStdString().c_str());
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "ComunicMessages Images Downloader 1.0");
QNetworkReply *reply = accessManager.get(request);
connect(reply, &QNetworkReply::finished, mHelper, &ImageLoadHelper::NetworkRequestFinished);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), mHelper, SLOT(NetworkError()));
connect(reply, &QNetworkReply::sslErrors, mHelper, &ImageLoadHelper::SSLErrors);
}
void ImageLoadHelper::ApplyImage(QLabel *label, const QString &url)
{
ApplyImage(label, QPixmap(GetImageStoragePath(url)));
}
void ImageLoadHelper::ApplyImage(QLabel *label, const QPixmap &pixmap)
{
label->setPixmap(pixmap);
}
bool ImageLoadHelper::IsDownloaded(const QString &url)
{
return QFile(GetImageStoragePath(url)).exists();
}
QString ImageLoadHelper::GetImageStoragePath(const QString &url)
{
//Containing directory
QString path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
+ QDir::separator() + REMOTE_IMAGES_CACHE_DIRECTORY;
//Check the directory exists. If not, create it
if(!FilesUtils::CreateDirectoryIfNotExists(path))
qFatal("Could not create images cache directory.");
//Add separator to path
path += QDir::separator();
//File name
path += QString(QCryptographicHash::hash(url.toStdString().c_str(), QCryptographicHash::Md5).toHex());
return path;
}

91
helpers/imageloadhelper.h Normal file
View File

@ -0,0 +1,91 @@
/**
* ImageLoadHelper - This helper is used to
* easily load remote images and caches them
*
* @author Pierre HUBERT
*/
#ifndef IMAGELOADHELPER_H
#define IMAGELOADHELPER_H
#include <QObject>
class QLabel;
class ImageLoadHelper : public QObject
{
Q_OBJECT
public:
/**
* Load an image into a label
*
* @param label The label where the image will be applied
* @param url The URL of the target image
*/
static void Load(QLabel *label, const QString &url);
signals:
private slots:
/**
* Slot called in case of SSL error
*/
void SSLErrors();
/**
* Slot called in case of network error
*/
void NetworkError();
/**
* Slot called when a network request finished
*/
void NetworkRequestFinished();
private:
//This constructor must be private
explicit ImageLoadHelper(QObject *parent = nullptr);
/**
* Download an image
*
* @param url The URL of the image to download
*/
static void Download(const QString &url);
/**
* Apply an image to a label
*
* @param label Target label which will receive the image
* @param url The remote URL of the image
*/
static void ApplyImage(QLabel *label, const QString &url);
/**
* Apply an image to a label
*
* @param label Target label which will receive the image
* @param pixamp The pixmap to apply to the label
*/
static void ApplyImage(QLabel *label, const QPixmap &pixmap);
/**
* Check out whether an image has been already downloaded
*
* @param url The URL of the target image
* @return TRUE for a success / FALSE else
*/
static bool IsDownloaded(const QString &url);
/**
* Get the storage path of a remote image
*
* @param url The URL of the remote image
* @return Full path to the image
*/
static QString GetImageStoragePath(const QString &url);
};
#endif // IMAGELOADHELPER_H