mirror of
				https://gitlab.com/comunic/comunicmessages
				synced 2025-11-04 12:14:05 +00:00 
			
		
		
		
	Can load remote images and cache them locally.
This commit is contained in:
		
							
								
								
									
										163
									
								
								helpers/imageloadhelper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								helpers/imageloadhelper.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										91
									
								
								helpers/imageloadhelper.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
		Reference in New Issue
	
	Block a user