Add support for saving embedded album covers

Fixes #286
This commit is contained in:
Jonas Kvinge
2021-02-26 21:03:51 +01:00
parent e4c89c1aed
commit 133f094d72
79 changed files with 3509 additions and 1804 deletions

194
src/core/imageutils.cpp Normal file
View File

@@ -0,0 +1,194 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QList>
#include <QBuffer>
#include <QVariant>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QImage>
#include <QImageReader>
#include <QPixmap>
#include <QPainter>
#include <QSize>
#include <QSettings>
#include "imageutils.h"
#include "core/utilities.h"
#include "core/tagreaderclient.h"
QStringList ImageUtils::kSupportedImageMimeTypes;
QStringList ImageUtils::kSupportedImageFormats;
QStringList ImageUtils::SupportedImageMimeTypes() {
if (kSupportedImageMimeTypes.isEmpty()) {
for (const QByteArray &mimetype : QImageReader::supportedMimeTypes()) {
kSupportedImageMimeTypes << mimetype;
}
}
return kSupportedImageMimeTypes;
}
QStringList ImageUtils::SupportedImageFormats() {
if (kSupportedImageFormats.isEmpty()) {
for (const QByteArray &filetype : QImageReader::supportedImageFormats()) {
kSupportedImageFormats << filetype;
}
}
return kSupportedImageFormats;
}
QList<QByteArray> ImageUtils::ImageFormatsForMimeType(const QByteArray &mimetype) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
return QImageReader::imageFormatsForMimeType(mimetype);
#else
if (mimetype == "image/bmp") return QList<QByteArray>() << "BMP";
else if (mimetype == "image/gif") return QList<QByteArray>() << "GIF";
else if (mimetype == "image/jpeg") return QList<QByteArray>() << "JPG";
else if (mimetype == "image/png") return QList<QByteArray>() << "PNG";
else return QList<QByteArray>();
#endif
}
QPixmap ImageUtils::TryLoadPixmap(const QUrl &art_automatic, const QUrl &art_manual, const QUrl &url) {
QPixmap ret;
if (!art_manual.path().isEmpty()) {
if (art_manual.path() == Song::kManuallyUnsetCover) return ret;
else if (art_manual.isLocalFile()) {
ret.load(art_manual.toLocalFile());
}
else if (art_manual.scheme().isEmpty()) {
ret.load(art_manual.path());
}
}
if (ret.isNull() && !art_automatic.path().isEmpty()) {
if (art_automatic.path() == Song::kEmbeddedCover && !url.isEmpty() && url.isLocalFile()) {
ret = QPixmap::fromImage(TagReaderClient::Instance()->LoadEmbeddedArtAsImageBlocking(url.toLocalFile()));
}
else if (art_automatic.isLocalFile()) {
ret.load(art_automatic.toLocalFile());
}
else if (art_automatic.scheme().isEmpty()) {
ret.load(art_automatic.path());
}
}
return ret;
}
QByteArray ImageUtils::SaveImageToJpegData(const QImage &image) {
if (image.isNull()) return QByteArray();
QByteArray image_data;
QBuffer buffer(&image_data);
if (buffer.open(QIODevice::WriteOnly)) {
image.save(&buffer, "JPEG");
buffer.close();
}
return image_data;
}
QImage ImageUtils::ScaleAndPad(const QImage &image, const bool scale, const bool pad, const int desired_height) {
if (image.isNull()) return image;
// Scale the image down
QImage image_scaled;
if (scale) {
image_scaled = image.scaled(QSize(desired_height, desired_height), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
else {
image_scaled = image;
}
// Pad the image to height x height
if (pad) {
QImage image_padded(desired_height, desired_height, QImage::Format_ARGB32);
image_padded.fill(0);
QPainter p(&image_padded);
p.drawImage((desired_height - image_scaled.width()) / 2, (desired_height - image_scaled.height()) / 2, image_scaled);
p.end();
image_scaled = image_padded;
}
return image_scaled;
}
QImage ImageUtils::CreateThumbnail(const QImage &image, const bool pad, const QSize size) {
if (image.isNull()) return image;
QImage image_thumbnail;
if (pad) {
image_thumbnail = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QImage image_padded(size, QImage::Format_ARGB32_Premultiplied);
image_padded.fill(0);
QPainter p(&image_padded);
p.drawImage((image_padded.width() - image_thumbnail.width()) / 2, (image_padded.height() - image_thumbnail.height()) / 2, image_thumbnail);
p.end();
image_thumbnail = image_padded;
}
else {
image_thumbnail = image.scaledToHeight(size.height(), Qt::SmoothTransformation);
}
return image_thumbnail;
}
QImage ImageUtils::GenerateNoCoverImage(const QSize size) {
QImage image(":/pictures/cdcase.png");
// Get a square version of the nocover image with some transparency:
QImage image_scaled = image.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QImage image_square(size, QImage::Format_ARGB32);
image_square.fill(0);
QPainter p(&image_square);
p.setOpacity(0.4);
p.drawImage((size.width() - image_scaled.width()) / 2, (size.height() - image_scaled.height()) / 2, image_scaled);
p.end();
return image_square;
}

51
src/core/imageutils.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef IMAGEUTILS_H
#define IMAGEUTILS_H
#include "config.h"
#include <QList>
#include <QByteArray>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QImage>
#include <QPixmap>
class ImageUtils {
private:
static QStringList kSupportedImageMimeTypes;
static QStringList kSupportedImageFormats;
public:
static QStringList SupportedImageMimeTypes();
static QStringList SupportedImageFormats();
static QList<QByteArray> ImageFormatsForMimeType(const QByteArray &mimetype);
static QByteArray SaveImageToJpegData(const QImage &image = QImage());
static QPixmap TryLoadPixmap(const QUrl &automatic, const QUrl &manual, const QUrl &url = QUrl());
static QImage ScaleAndPad(const QImage &image, const bool scale, const bool pad, const int desired_height);
static QImage CreateThumbnail(const QImage &image, const bool pad, const QSize size);
static QImage GenerateNoCoverImage(const QSize size = QSize());
};
#endif // IMAGEUTILS_H

View File

@@ -143,6 +143,7 @@
#include "covermanager/albumcoverloaderresult.h"
#include "covermanager/currentalbumcoverloader.h"
#include "covermanager/coverproviders.h"
#include "covermanager/albumcoverimageresult.h"
#include "lyrics/lyricsproviders.h"
#ifndef Q_OS_WIN
# include "device/devicemanager.h"
@@ -613,6 +614,8 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSDBase *osd
QObject::connect(album_cover_choice_controller_->cover_from_url_action(), &QAction::triggered, this, &MainWindow::LoadCoverFromURL);
QObject::connect(album_cover_choice_controller_->search_for_cover_action(), &QAction::triggered, this, &MainWindow::SearchForCover);
QObject::connect(album_cover_choice_controller_->unset_cover_action(), &QAction::triggered, this, &MainWindow::UnsetCover);
QObject::connect(album_cover_choice_controller_->clear_cover_action(), &QAction::triggered, this, &MainWindow::ClearCover);
QObject::connect(album_cover_choice_controller_->delete_cover_action(), &QAction::triggered, this, &MainWindow::DeleteCover);
QObject::connect(album_cover_choice_controller_->show_cover_action(), &QAction::triggered, this, &MainWindow::ShowCover);
QObject::connect(album_cover_choice_controller_->search_cover_auto_action(), &QAction::triggered, this, &MainWindow::SearchCoverAutomatically);
QObject::connect(album_cover_choice_controller_->search_cover_auto_action(), &QAction::toggled, this, &MainWindow::ToggleSearchCoverAuto);
@@ -1234,7 +1237,7 @@ void MainWindow::MediaStopped() {
song_playing_ = Song();
song_ = Song();
image_original_ = QImage();
album_cover_ = AlbumCoverImageResult();
app_->scrobbler()->ClearPlaying();
@@ -1312,6 +1315,14 @@ void MainWindow::SongChanged(const Song &song) {
SendNowPlaying();
const bool enable_cover_options = song.url().isLocalFile() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_cover_options);
album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_cover_options);
album_cover_choice_controller_->search_for_cover_action()->setEnabled(enable_cover_options);
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_cover_options);
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_cover_options);
album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_cover_options);
}
void MainWindow::TrackSkipped(PlaylistItemPtr item) {
@@ -2073,7 +2084,7 @@ void MainWindow::RenumberTracks() {
song.set_track(track);
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); });
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection);
}
++track;
}
@@ -2085,7 +2096,7 @@ void MainWindow::SongSaveComplete(TagReaderReply *reply, const QPersistentModelI
if (reply->is_successful() && idx.isValid()) {
app_->playlist_manager()->current()->ReloadItems(QList<int>()<< idx.row());
}
reply->deleteLater();
metaObject()->invokeMethod(reply, "deleteLater", Qt::QueuedConnection);
}
@@ -2104,7 +2115,7 @@ void MainWindow::SelectionSetValue() {
if (Playlist::set_column_value(song, column, column_value)) {
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); });
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection);
}
}
@@ -2914,15 +2925,23 @@ void MainWindow::SearchForCover() {
}
void MainWindow::SaveCoverToFile() {
album_cover_choice_controller_->SaveCoverToFileManual(song_, image_original_);
album_cover_choice_controller_->SaveCoverToFileManual(song_, album_cover_);
}
void MainWindow::UnsetCover() {
album_cover_choice_controller_->UnsetCover(&song_);
}
void MainWindow::ClearCover() {
album_cover_choice_controller_->ClearCover(&song_);
}
void MainWindow::DeleteCover() {
album_cover_choice_controller_->DeleteCover(&song_);
}
void MainWindow::ShowCover() {
album_cover_choice_controller_->ShowCover(song_, image_original_);
album_cover_choice_controller_->ShowCover(song_, album_cover_.image);
}
void MainWindow::SearchCoverAutomatically() {
@@ -2936,9 +2955,9 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult
if (song != song_playing_) return;
song_ = song;
image_original_ = result.image_original;
album_cover_ = result.album_cover;
emit AlbumCoverReady(song, result.image_original);
emit AlbumCoverReady(song, result.album_cover.image);
GetCoverAutomatically();

View File

@@ -61,6 +61,7 @@
#include "settings/settingsdialog.h"
#include "settings/behavioursettingspage.h"
#include "covermanager/albumcoverloaderresult.h"
#include "covermanager/albumcoverimageresult.h"
class About;
class Console;
@@ -255,6 +256,8 @@ class MainWindow : public QMainWindow, public PlatformInterface {
void LoadCoverFromURL();
void SearchForCover();
void UnsetCover();
void ClearCover();
void DeleteCover();
void ShowCover();
void SearchCoverAutomatically();
void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result);
@@ -386,7 +389,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
Song song_;
Song song_playing_;
QImage image_original_;
AlbumCoverImageResult album_cover_;
int exit_count_;
bool delete_files_;

View File

@@ -115,10 +115,10 @@ void RegisterMetaTypes() {
qRegisterMetaType<PlaylistSequence::ShuffleMode>("PlaylistSequence::ShuffleMode");
qRegisterMetaType<AlbumCoverLoaderResult>("AlbumCoverLoaderResult");
qRegisterMetaType<AlbumCoverLoaderResult::Type>("AlbumCoverLoaderResult::Type");
qRegisterMetaType<CoverSearchResult>("CoverSearchResult");
qRegisterMetaType<CoverProviderSearchResult>("CoverProviderSearchResult");
qRegisterMetaType<CoverSearchStatistics>("CoverSearchStatistics");
qRegisterMetaType<QList<CoverSearchResult> >("QList<CoverSearchResult>");
qRegisterMetaType<CoverSearchResults>("CoverSearchResults");
qRegisterMetaType<QList<CoverProviderSearchResult> >("QList<CoverProviderSearchResult>");
qRegisterMetaType<CoverProviderSearchResults>("CoverProviderSearchResults");
qRegisterMetaType<Equalizer::Params>("Equalizer::Params");
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
qRegisterMetaTypeStreamOperators<Equalizer::Params>("Equalizer::Params");

View File

@@ -394,8 +394,8 @@ void Mpris2::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &re
AddMetadata("mpris:trackid", current_track_id(), &last_metadata_);
QUrl cover_url;
if (result.cover_url.isValid() && result.cover_url.isLocalFile() && QFile(result.cover_url.toLocalFile()).exists()) {
cover_url = result.cover_url;
if (result.album_cover.cover_url.isValid() && result.album_cover.cover_url.isLocalFile() && QFile(result.album_cover.cover_url.toLocalFile()).exists()) {
cover_url = result.album_cover.cover_url;
}
else if (result.temp_cover_url.isValid() && result.temp_cover_url.isLocalFile()) {
cover_url = result.temp_cover_url;

View File

@@ -183,7 +183,7 @@ class Mpris2 : public QObject {
// Methods
void ActivatePlaylist(const QDBusObjectPath &playlist_id);
QList<MprisPlaylist> GetPlaylists(quint32 index, quint32 max_count, const QString &order, bool reverse_order);
MprisPlaylistList GetPlaylists(quint32 index, quint32 max_count, const QString &order, bool reverse_order);
signals:
// Player

View File

@@ -341,10 +341,22 @@ bool Song::compilation_on() const { return d->compilation_on_; }
const QUrl &Song::art_automatic() const { return d->art_automatic_; }
const QUrl &Song::art_manual() const { return d->art_manual_; }
bool Song::has_manually_unset_cover() const { return d->art_manual_.path() == kManuallyUnsetCover; }
void Song::manually_unset_cover() { d->art_manual_ = QUrl::fromLocalFile(kManuallyUnsetCover); }
void Song::set_manually_unset_cover() { d->art_manual_ = QUrl::fromLocalFile(kManuallyUnsetCover); }
bool Song::has_embedded_cover() const { return d->art_automatic_.path() == kEmbeddedCover; }
void Song::set_embedded_cover() { d->art_automatic_ = QUrl::fromLocalFile(kEmbeddedCover); }
void Song::clear_art_automatic() { d->art_automatic_.clear(); }
void Song::clear_art_manual() { d->art_manual_.clear(); }
bool Song::save_embedded_cover_supported(const FileType filetype) {
return filetype == FileType_FLAC ||
filetype == FileType_OggVorbis ||
filetype == FileType_MPEG ||
filetype == FileType_MP4;
}
const QUrl &Song::stream_url() const { return d->stream_url_; }
const QUrl &Song::effective_stream_url() const { return !d->stream_url_.isEmpty() && d->stream_url_.isValid() ? d->stream_url_ : d->url_; }
const QImage &Song::image() const { return d->image_; }
@@ -382,6 +394,8 @@ bool Song::art_manual_is_valid() const {
);
}
bool Song::has_valid_art() const { return art_automatic_is_valid() || art_manual_is_valid(); }
const QString &Song::error() const { return d->error_; }
void Song::set_id(int id) { d->id_ = id; }
@@ -1054,13 +1068,19 @@ void Song::InitArtManual() {
if (QFile::exists(path)) {
d->art_manual_ = QUrl::fromLocalFile(path);
}
else if (d->url_.isLocalFile()) { // Pick the first image file in the album directory.
QFileInfo file(d->url_.toLocalFile());
QDir dir(file.path());
QStringList files = dir.entryList(QStringList() << "*.jpg" << "*.png" << "*.gif" << "*.jpeg", QDir::Files|QDir::Readable, QDir::Name);
if (files.count() > 0) {
d->art_manual_ = QUrl::fromLocalFile(file.path() + QDir::separator() + files.first());
}
}
}
void Song::InitArtAutomatic() {
if (d->source_ == Source_LocalFile && d->url_.isLocalFile() && d->art_automatic_.isEmpty()) {
// Pick the first image file in the album directory.
QFileInfo file(d->url_.toLocalFile());
QDir dir(file.path());
QStringList files = dir.entryList(QStringList() << "*.jpg" << "*.png" << "*.gif" << "*.jpeg", QDir::Files|QDir::Readable, QDir::Name);
if (files.count() > 0) {
d->art_automatic_ = QUrl::fromLocalFile(file.path() + QDir::separator() + files.first());
}
}
@@ -1491,11 +1511,15 @@ bool Song::IsMetadataEqual(const Song &other) const {
d->bitrate_ == other.d->bitrate_ &&
d->samplerate_ == other.d->samplerate_ &&
d->bitdepth_ == other.d->bitdepth_ &&
d->art_automatic_ == other.d->art_automatic_ &&
d->art_manual_ == other.d->art_manual_ &&
d->cue_path_ == other.d->cue_path_;
}
bool Song::IsMetadataAndArtEqual(const Song &other) const {
return IsMetadataEqual(other) && d->art_automatic_ == other.d->art_automatic_ && d->art_manual_ == other.d->art_manual_;
}
bool Song::IsEditable() const {
return d->valid_ && !d->url_.isEmpty() && !is_stream() && d->source_ != Source_Unknown && d->filetype_ != FileType_Unknown && !has_cue();
}

View File

@@ -159,6 +159,7 @@ class Song {
void InitFromQuery(const SqlRow &query, bool reliable_metadata, int col = 0);
void InitFromFilePartial(const QString &filename); // Just store the filename: incomplete but fast
void InitArtManual(); // Check if there is already a art in the cache and store the filename in art_manual
void InitArtAutomatic();
bool MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle);
@@ -255,6 +256,7 @@ class Song {
bool is_metadata_good() const;
bool art_automatic_is_valid() const;
bool art_manual_is_valid() const;
bool has_valid_art() const;
bool is_compilation() const;
// Playlist views are special because you don't want to fill in album artists automatically for compilations, but you do for normal albums:
@@ -264,13 +266,19 @@ class Song {
// Returns true if this Song had it's cover manually unset by user.
bool has_manually_unset_cover() const;
// This method represents an explicit request to unset this song's cover.
void manually_unset_cover();
void set_manually_unset_cover();
// Returns true if this song (it's media file) has an embedded cover.
bool has_embedded_cover() const;
// Sets a flag saying that this song (it's media file) has an embedded cover.
void set_embedded_cover();
void clear_art_automatic();
void clear_art_manual();
static bool save_embedded_cover_supported(const FileType filetype);
bool save_embedded_cover_supported() const { return url().isLocalFile() && save_embedded_cover_supported(filetype()) && !has_cue(); };
const QUrl &stream_url() const;
const QUrl &effective_stream_url() const;
const QImage &image() const;
@@ -355,6 +363,7 @@ class Song {
// Comparison functions
bool IsMetadataEqual(const Song &other) const;
bool IsMetadataAndArtEqual(const Song &other) const;
bool IsOnSameAlbum(const Song &other) const;
bool IsSimilar(const Song &other) const;

View File

@@ -102,7 +102,7 @@ void StandardItemIconLoader::AlbumCoverLoaded(const quint64 id, const AlbumCover
QStandardItem *item = pending_covers_.take(id);
if (!item) return;
if (!result.image_scaled.isNull()) {
if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type_ManuallyUnset) {
item->setIcon(QIcon(QPixmap::fromImage(result.image_scaled)));
}

View File

@@ -172,7 +172,24 @@ bool TagReaderClient::IsMediaFileBlocking(const QString &filename) {
}
QImage TagReaderClient::LoadEmbeddedArtBlocking(const QString &filename) {
QByteArray TagReaderClient::LoadEmbeddedArtBlocking(const QString &filename) {
Q_ASSERT(QThread::currentThread() != thread());
QByteArray ret;
TagReaderReply *reply = LoadEmbeddedArt(filename);
if (reply->WaitForFinished()) {
const std::string &data_str = reply->message().load_embedded_art_response().data();
ret = QByteArray(data_str.data(), data_str.size());
}
metaObject()->invokeMethod(reply, "deleteLater", Qt::QueuedConnection);
return ret;
}
QImage TagReaderClient::LoadEmbeddedArtAsImageBlocking(const QString &filename) {
Q_ASSERT(QThread::currentThread() != thread());

View File

@@ -63,7 +63,8 @@ class TagReaderClient : public QObject {
void ReadFileBlocking(const QString &filename, Song *song);
bool SaveFileBlocking(const QString &filename, const Song &metadata);
bool IsMediaFileBlocking(const QString &filename);
QImage LoadEmbeddedArtBlocking(const QString &filename);
QByteArray LoadEmbeddedArtBlocking(const QString &filename);
QImage LoadEmbeddedArtAsImageBlocking(const QString &filename);
bool SaveEmbeddedArtBlocking(const QString &filename, const QByteArray &data);
// TODO: Make this not a singleton

View File

@@ -57,7 +57,7 @@
#include <QtEvents>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QImageReader>
#include <QMimeDatabase>
#include <QtDebug>
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
# include <QRandomGenerator>
@@ -102,9 +102,6 @@
namespace Utilities {
QStringList kSupportedImageMimeTypes;
QStringList kSupportedImageFormats;
static QString tr(const char *str) {
return QCoreApplication::translate("", str);
}
@@ -945,41 +942,23 @@ bool IsColorDark(const QColor &color) {
return ((30 * color.red() + 59 * color.green() + 11 * color.blue()) / 100) <= 130;
}
QStringList SupportedImageMimeTypes() {
QByteArray ReadDataFromFile(const QString &filename) {
if (kSupportedImageMimeTypes.isEmpty()) {
for (const QByteArray &mimetype : QImageReader::supportedMimeTypes()) {
kSupportedImageMimeTypes << mimetype;
}
QFile file(filename);
QByteArray data;
if (file.open(QIODevice::ReadOnly)) {
data = file.readAll();
file.close();
}
return kSupportedImageMimeTypes;
return data;
}
QStringList SupportedImageFormats() {
QString MimeTypeFromData(const QByteArray &data) {
if (kSupportedImageFormats.isEmpty()) {
for (const QByteArray &filetype : QImageReader::supportedImageFormats()) {
kSupportedImageFormats << filetype;
}
}
if (data.isEmpty()) return QString();
return kSupportedImageFormats;
}
QList<QByteArray> ImageFormatsForMimeType(const QByteArray &mimetype) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
return QImageReader::imageFormatsForMimeType(mimetype);
#else
if (mimetype == "image/bmp") return QList<QByteArray>() << "BMP";
else if (mimetype == "image/gif") return QList<QByteArray>() << "GIF";
else if (mimetype == "image/jpeg") return QList<QByteArray>() << "JPG";
else if (mimetype == "image/png") return QList<QByteArray>() << "PNG";
else return QList<QByteArray>();
#endif
return QMimeDatabase().mimeTypeForData(data).name();
}

View File

@@ -143,9 +143,8 @@ QString ReplaceVariable(const QString &variable, const Song &song, const QString
bool IsColorDark(const QColor &color);
QStringList SupportedImageMimeTypes();
QStringList SupportedImageFormats();
QList<QByteArray> ImageFormatsForMimeType(const QByteArray &mimetype);
QByteArray ReadDataFromFile(const QString &filename);
QString MimeTypeFromData(const QByteArray &data);
} // namespace