mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-02-04 05:09:27 +00:00
Create thumbnails into memory instead of disk.
Clean unused headers.
This commit is contained in:
parent
d3b3a5ac37
commit
c8337d9dda
20 changed files with 71 additions and 181 deletions
|
|
@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Fetch remote provisioning from URI handler and with confirmation.
|
||||
- Emojis picker.
|
||||
- Text edit in chat can now understand rich texts.
|
||||
- Create thumbnails into memory instead of disk.
|
||||
|
||||
### Removed
|
||||
- Picture zoom on mouse over.
|
||||
|
|
|
|||
|
|
@ -298,9 +298,6 @@ string Paths::getRootCaFilePath () {
|
|||
return getReadableFilePath(getAppRootCaFilePath());
|
||||
}
|
||||
|
||||
string Paths::getThumbnailsDirPath () {
|
||||
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + Constants::PathThumbnails);
|
||||
}
|
||||
string Paths::getToolsDirPath () {
|
||||
return getWritableDirPath(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + Constants::PathTools);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ namespace Paths {
|
|||
std::string getPluginsAppDirPath ();
|
||||
QStringList getPluginsAppFolders();
|
||||
std::string getRootCaFilePath ();
|
||||
std::string getThumbnailsDirPath ();
|
||||
std::string getToolsDirPath ();
|
||||
std::string getUserCertificatesDirPath ();
|
||||
std::string getZrtpDataFilePath ();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "components/other/images/ImageModel.hpp"
|
||||
|
||||
#include "ThumbnailProvider.hpp"
|
||||
|
||||
|
|
@ -31,11 +31,10 @@ ThumbnailProvider::ThumbnailProvider () : QQuickImageProvider(
|
|||
QQmlImageProviderBase::Image,
|
||||
QQmlImageProviderBase::ForceAsynchronousImageLoading
|
||||
) {
|
||||
mThumbnailsPath = Utils::coreStringToAppString(Paths::getThumbnailsDirPath());
|
||||
}
|
||||
|
||||
QImage ThumbnailProvider::requestImage (const QString &id, QSize *size, const QSize &) {
|
||||
QImage image(mThumbnailsPath + id);
|
||||
*size = image.size();
|
||||
return image;
|
||||
QImage image = ImageModel::createThumbnail(id);
|
||||
*size = image.size();
|
||||
return image;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@ public:
|
|||
QImage requestImage (const QString &id, QSize *size, const QSize &requestedSize) override;
|
||||
|
||||
static const QString ProviderId;
|
||||
|
||||
private:
|
||||
QString mThumbnailsPath;
|
||||
};
|
||||
|
||||
#endif // THUMBNAIL_PROVIDER_H_
|
||||
|
|
|
|||
|
|
@ -263,17 +263,8 @@ void ChatMessageModel::resendMessage (){
|
|||
}
|
||||
|
||||
void ChatMessageModel::deleteEvent(){
|
||||
if (mChatMessage && mChatMessage->getFileTransferInformation()) {// Remove thumbnail
|
||||
if (mChatMessage && mChatMessage->getFileTransferInformation()) {
|
||||
mChatMessage->cancelFileTransfer();
|
||||
QString appdata = QString::fromStdString(mChatMessage->getAppdata());
|
||||
QStringList fields = appdata.split(':');
|
||||
|
||||
if(fields[0].size() > 0) {
|
||||
QString thumbnailPath = QString::fromStdString(Paths::getThumbnailsDirPath()) + fields[0];
|
||||
if (!QFile::remove(thumbnailPath))
|
||||
qWarning() << QStringLiteral("Unable to remove `%1`.").arg(thumbnailPath);
|
||||
}
|
||||
mChatMessage->setAppdata("");// Remove completely Thumbnail from the message
|
||||
}
|
||||
if(mChatMessage)
|
||||
mChatMessage->getChatRoom()->deleteMessage(mChatMessage);
|
||||
|
|
|
|||
|
|
@ -26,19 +26,7 @@
|
|||
#include <QDateTime>
|
||||
|
||||
// =============================================================================
|
||||
/*
|
||||
class Thumbnail{
|
||||
public:
|
||||
Thumbnail();
|
||||
QString mId;
|
||||
QString mPath;
|
||||
|
||||
QString toString()const;
|
||||
void fromString(const QString& );
|
||||
static QString toString(const QVector<Thumbnail>& );
|
||||
static QVector<Thumbnail> fromListString(const QString& );
|
||||
};
|
||||
*/
|
||||
|
||||
#include "components/chat-room/ChatRoomModel.hpp"
|
||||
#include "ChatEvent.hpp"
|
||||
#include "components/participant-imdn/ParticipantImdnStateListModel.hpp"
|
||||
|
|
@ -58,7 +46,7 @@ public:
|
|||
ChatMessageModel (std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent = nullptr);
|
||||
virtual ~ChatMessageModel();
|
||||
|
||||
class AppDataManager{// Used to manage appdata to store persistant data like created thumbnails
|
||||
class AppDataManager{// Used to manage appdata to store persistant data
|
||||
public:
|
||||
AppDataManager(const QString&);
|
||||
QMap<QString, QString> mData;// Path / ID
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@
|
|||
#include "ChatRoomListener.hpp"
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
#include "components/calls/CallsListModel.hpp"
|
||||
#include "components/chat/ChatModel.hpp"
|
||||
#include "components/chat-events/ChatCallModel.hpp"
|
||||
|
|
@ -53,8 +51,6 @@
|
|||
#include "components/content/ContentModel.hpp"
|
||||
#include "components/core/CoreHandlers.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/notifier/Notifier.hpp"
|
||||
#include "components/settings/AccountSettingsModel.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
#include "components/participant/ParticipantModel.hpp"
|
||||
#include "components/participant/ParticipantListModel.hpp"
|
||||
|
|
@ -64,9 +60,7 @@
|
|||
#include "components/timeline/TimelineModel.hpp"
|
||||
#include "components/timeline/TimelineListModel.hpp"
|
||||
#include "components/core/event-count-notifier/AbstractEventCountNotifier.hpp"
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Constants.hpp"
|
||||
#include "utils/LinphoneEnums.hpp"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,15 +26,7 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
|
||||
#include "components/chat-events/ChatMessageModel.hpp"
|
||||
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Constants.hpp"
|
||||
#include "components/Components.hpp"
|
||||
#include "components/content/ContentListModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,9 @@
|
|||
#include <QMessageBox>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
|
||||
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "components/participant/ParticipantListModel.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Constants.hpp"
|
||||
#include "components/Components.hpp"
|
||||
|
||||
|
||||
void ConferenceModel::connectTo(ConferenceListener * listener){
|
||||
connect(listener, &ConferenceListener::activeSpeakerParticipantDevice, this, &ConferenceModel::onActiveSpeakerParticipantDevice);
|
||||
|
|
|
|||
|
|
@ -35,34 +35,12 @@
|
|||
#include <qqmlapplicationengine.h>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
#include "components/calls/CallsListModel.hpp"
|
||||
#include "components/chat-events/ChatCallModel.hpp"
|
||||
#include "components/chat-events/ChatEvent.hpp"
|
||||
#include "components/chat-events/ChatMessageModel.hpp"
|
||||
#include "components/chat-events/ChatNoticeModel.hpp"
|
||||
#include "components/contact/ContactModel.hpp"
|
||||
#include "components/contact/VcardModel.hpp"
|
||||
#include "components/contacts/ContactsListModel.hpp"
|
||||
#include "components/conferenceScheduler/ConferenceScheduler.hpp"
|
||||
#include "components/core/CoreHandlers.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/notifier/Notifier.hpp"
|
||||
#include "components/other/timeZone/TimeZoneModel.hpp"
|
||||
#include "components/settings/AccountSettingsModel.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
#include "components/participant/ParticipantModel.hpp"
|
||||
#include "components/participant/ParticipantListModel.hpp"
|
||||
#include "components/presence/Presence.hpp"
|
||||
#include "components/recorder/RecorderManager.hpp"
|
||||
#include "components/recorder/RecorderModel.hpp"
|
||||
#include "components/timeline/TimelineModel.hpp"
|
||||
#include "components/timeline/TimelineListModel.hpp"
|
||||
#include "components/core/event-count-notifier/AbstractEventCountNotifier.hpp"
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Constants.hpp"
|
||||
#include "utils/LinphoneEnums.hpp"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ void ContentListModel::remove(ContentModel * model){
|
|||
int count = 0;
|
||||
for(auto it = mList.begin() ; it != mList.end() ; ++count, ++it) {
|
||||
if( it->get() == model) {
|
||||
model->removeThumbnail();
|
||||
removeRow(count, QModelIndex());
|
||||
return;
|
||||
}
|
||||
|
|
@ -96,10 +95,6 @@ void ContentListModel::remove(ContentModel * model){
|
|||
}
|
||||
|
||||
void ContentListModel::clear(){
|
||||
// Delete thumbnails
|
||||
for(auto contentModel : mList){
|
||||
contentModel.objectCast<ContentModel>()->removeThumbnail();
|
||||
}
|
||||
resetData();
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +102,6 @@ void ContentListModel::removeDownloadedFiles(){
|
|||
for(auto model : mList){
|
||||
auto contentModel = model.objectCast<ContentModel>();
|
||||
contentModel->removeDownloadedFile();
|
||||
contentModel->removeThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,20 +22,18 @@
|
|||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QDesktopServices>
|
||||
#include <QImageReader>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
|
||||
#include "components/chat-events/ChatMessageModel.hpp"
|
||||
#include "components/conferenceInfo/ConferenceInfoModel.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
#include "utils/Constants.hpp"
|
||||
#include "components/Components.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -158,91 +156,13 @@ void ContentModel::createThumbnail (const bool& force) {
|
|||
if(force || isFile() || isFileEncrypted() || isFileTransfer()){
|
||||
QString id;
|
||||
QString path = getFilePath();
|
||||
|
||||
auto appdata = ChatMessageModel::AppDataManager(mChatMessageModel ? QString::fromStdString(mChatMessageModel->getChatMessage()->getAppdata()) : "");
|
||||
|
||||
if(!appdata.mData.contains(path)
|
||||
|| !QFileInfo(QString::fromStdString(Paths::getThumbnailsDirPath())+appdata.mData[path]).isFile()){
|
||||
// File don't exist. Create the thumbnail
|
||||
QImage originalImage(path);
|
||||
|
||||
if( originalImage.isNull()){// Try to determine format from headers
|
||||
QImageReader reader(path);
|
||||
reader.setDecideFormatFromContent(true);
|
||||
QByteArray format = reader.format();
|
||||
if(!format.isEmpty())
|
||||
originalImage = QImage(path, format);
|
||||
}
|
||||
if (!originalImage.isNull()){
|
||||
int rotation = 0;
|
||||
QExifImageHeader exifImageHeader;
|
||||
if (exifImageHeader.loadFromJpeg(path))
|
||||
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
|
||||
// Fill with color to replace transparency with white color instead of black (default).
|
||||
QImage image(originalImage.size(), originalImage.format());
|
||||
image.fill(QColor(Qt::white).rgb());
|
||||
QPainter painter(&image);
|
||||
painter.drawImage(0, 0, originalImage);
|
||||
//--------------------
|
||||
double factor = image.width() / (double)image.height();
|
||||
if(factor < 0.2 || factor > 5){
|
||||
qInfo() << QStringLiteral("Cannot create thumbnails because size factor (%1) is too low/much of: `%2`.").arg(factor).arg(path);
|
||||
}else {
|
||||
QImage thumbnail = image.scaled(
|
||||
Constants::ThumbnailImageFileWidth, Constants::ThumbnailImageFileHeight,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation
|
||||
);
|
||||
|
||||
if (rotation != 0) {
|
||||
QTransform transform;
|
||||
if (rotation == 3 || rotation == 4)
|
||||
transform.rotate(180);
|
||||
else if (rotation == 5 || rotation == 6)
|
||||
transform.rotate(90);
|
||||
else if (rotation == 7 || rotation == 8)
|
||||
transform.rotate(-90);
|
||||
thumbnail = thumbnail.transformed(transform);
|
||||
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
|
||||
thumbnail = thumbnail.mirrored(true, false);
|
||||
}
|
||||
QString uuid = QUuid::createUuid().toString();
|
||||
id = QStringLiteral("%1.jpg").arg(uuid.mid(1, uuid.length() - 2));
|
||||
|
||||
if (!thumbnail.save(QString::fromStdString(Paths::getThumbnailsDirPath()) + id , "jpg", 100)) {
|
||||
qWarning() << QStringLiteral("Unable to create thumbnail of: `%1`.").arg(path);
|
||||
}else{
|
||||
appdata.mData[path] = id;
|
||||
mAppData.mData[path] = id;
|
||||
if(mChatMessageModel)
|
||||
mChatMessageModel->getChatMessage()->setAppdata(appdata.toString().toStdString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( path != ""){
|
||||
setWasDownloaded( !path.isEmpty() && QFileInfo(path).isFile());
|
||||
if(appdata.mData.contains(path) && !appdata.mData[path].isEmpty())
|
||||
setThumbnail(QStringLiteral("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(appdata.mData[path]));
|
||||
setThumbnail(QStringLiteral("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContentModel::removeThumbnail(){
|
||||
for(QMap<QString, QString>::iterator itData = mAppData.mData.begin() ; itData != mAppData.mData.end() ; ++itData){
|
||||
QString thumbnailPath = QString::fromStdString(Paths::getThumbnailsDirPath()) +itData.value();
|
||||
if( QFileInfo(thumbnailPath).isFile()){
|
||||
QFile(thumbnailPath).remove();
|
||||
}
|
||||
}
|
||||
QString backup;
|
||||
if( mAppData.mData.contains("receivedTime"))
|
||||
backup = mAppData.mData["receivedTime"];
|
||||
mAppData.mData.clear();
|
||||
if( !backup.isEmpty())
|
||||
mAppData.mData["receivedTime"] = backup;
|
||||
}
|
||||
|
||||
void ContentModel::removeDownloadedFile(){
|
||||
QString path = getFilePath();
|
||||
if( path != ""){
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ public:
|
|||
Q_INVOKABLE int getFileDuration() const;
|
||||
|
||||
void createThumbnail (const bool& force = false);
|
||||
void removeThumbnail ();
|
||||
void removeDownloadedFile();
|
||||
|
||||
Q_INVOKABLE void downloadFile();
|
||||
|
|
|
|||
|
|
@ -31,14 +31,8 @@
|
|||
#include <QUrlQuery>
|
||||
#include <QImageReader>
|
||||
|
||||
#include "app/App.hpp"
|
||||
#include "app/paths/Paths.hpp"
|
||||
#include "app/providers/ThumbnailProvider.hpp"
|
||||
#include "components/core/CoreHandlers.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/notifier/Notifier.hpp"
|
||||
#include "components/settings/SettingsModel.hpp"
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "HistoryModel.hpp"
|
||||
|
|
|
|||
|
|
@ -20,12 +20,15 @@
|
|||
#include "ImageModel.hpp"
|
||||
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QImageReader>
|
||||
#include <QPainter>
|
||||
#include "app/App.hpp"
|
||||
|
||||
#include "utils/Utils.hpp"
|
||||
|
||||
#include "components/Components.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "utils/QExifImageHeader.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -73,3 +76,53 @@ void ImageModel::setDescription(const QString& data){
|
|||
void ImageModel::setUrl(const QUrl& url){
|
||||
setPath(url.toString(QUrl::RemoveScheme));
|
||||
}
|
||||
|
||||
QImage ImageModel::createThumbnail(const QString& path){
|
||||
QImage thumbnail;
|
||||
if(QFileInfo(path).isFile()){
|
||||
QImage originalImage(path);
|
||||
|
||||
if( originalImage.isNull()){// Try to determine format from headers
|
||||
QImageReader reader(path);
|
||||
reader.setDecideFormatFromContent(true);
|
||||
QByteArray format = reader.format();
|
||||
if(!format.isEmpty())
|
||||
originalImage = QImage(path, format);
|
||||
}
|
||||
if (!originalImage.isNull()){
|
||||
int rotation = 0;
|
||||
QExifImageHeader exifImageHeader;
|
||||
if (exifImageHeader.loadFromJpeg(path))
|
||||
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
|
||||
// Fill with color to replace transparency with white color instead of black (default).
|
||||
QImage image(originalImage.size(), originalImage.format());
|
||||
image.fill(QColor(Qt::white).rgb());
|
||||
QPainter painter(&image);
|
||||
painter.drawImage(0, 0, originalImage);
|
||||
//--------------------
|
||||
double factor = image.width() / (double)image.height();
|
||||
if(factor < 0.2 || factor > 5){
|
||||
qInfo() << QStringLiteral("Cannot create thumbnails because size factor (%1) is too low/much of: `%2`.").arg(factor).arg(path);
|
||||
}else {
|
||||
thumbnail = image.scaled(
|
||||
Constants::ThumbnailImageFileWidth, Constants::ThumbnailImageFileHeight,
|
||||
Qt::KeepAspectRatio, Qt::SmoothTransformation
|
||||
);
|
||||
|
||||
if (rotation != 0) {
|
||||
QTransform transform;
|
||||
if (rotation == 3 || rotation == 4)
|
||||
transform.rotate(180);
|
||||
else if (rotation == 5 || rotation == 6)
|
||||
transform.rotate(90);
|
||||
else if (rotation == 7 || rotation == 8)
|
||||
transform.rotate(-90);
|
||||
thumbnail = thumbnail.transformed(transform);
|
||||
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
|
||||
thumbnail = thumbnail.mirrored(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return thumbnail;
|
||||
}
|
||||
|
|
@ -43,11 +43,12 @@ public:
|
|||
QString getDescription() const;
|
||||
QString getId() const;
|
||||
|
||||
|
||||
void setPath(const QString& path);
|
||||
void setDescription(const QString& description);
|
||||
Q_INVOKABLE void setUrl(const QUrl& url);
|
||||
|
||||
static QImage createThumbnail(const QString& path);
|
||||
|
||||
signals:
|
||||
void pathChanged();
|
||||
void descriptionChanged();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ constexpr char Constants::PathPlugins[];
|
|||
#endif
|
||||
constexpr char Constants::PathPluginsApp[];
|
||||
constexpr char Constants::PathSounds[];
|
||||
constexpr char Constants::PathThumbnails[];
|
||||
constexpr char Constants::PathUserCertificates[];
|
||||
|
||||
constexpr char Constants::PathCallHistoryList[];
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ public:
|
|||
#endif
|
||||
static constexpr char PathPluginsApp[] = "app/";
|
||||
static constexpr char PathSounds[] = "/sounds/" EXECUTABLE_NAME;
|
||||
static constexpr char PathThumbnails[] = "/thumbnails/";
|
||||
static constexpr char PathUserCertificates[] = "/usr-crt/";
|
||||
|
||||
static constexpr char PathCallHistoryList[] = "/call-history.db";
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ Item{
|
|||
running: grid.auxItemDisplayed<mainItem.maxIndex-grid.auxItemsCount
|
||||
property int lastCount: 0
|
||||
onTriggered: {
|
||||
console.log(grid.auxItemDisplayed - lastCount)
|
||||
console.log("Loaded emojis : " +(grid.auxItemDisplayed - lastCount))
|
||||
lastCount = grid.auxItemDisplayed
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue