Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/qt/util/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 9 kB image not shown  

Quelle  covergenerator.cpp   Sprache: C

 

/*****************************************************************************
 * Copyright (C) 2021 VLC authors and VideoLAN
 *
 * Authors: Benjamin Arnaud <bunjee@omega.gg>
 *
 * This program 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 2 of the License, or
 * ( at your option ) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#include "covergenerator.hpp"

// VLC includes
#include "qt.hpp"

// MediaLibrary includes
#include "medialibrary/mlhelper.hpp"

#include <cmath>

// Qt includes
#include <QDir>
#include <QImageReader>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QGraphicsBlurEffect>
#include <QUrl>
#include <QQmlFile>

// Qt private exported function
QT_BEGIN_NAMESPACE
extern void VLC_WEAK qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0);
QT_END_NAMESPACE

//-------------------------------------------------------------------------------------------------
// Static variables

static const QString COVERGENERATOR_STORAGE = "/art/qt-covers";

static const int COVERGENERATOR_COUNT = 2;

static const QString COVERGENERATOR_DEFAULT = ":/placeholder/noart_albumCover.svg";

//-------------------------------------------------------------------------------------------------
// Ctor / dtor
//-------------------------------------------------------------------------------------------------

CoverGenerator::CoverGenerator()
    : m_countX(COVERGENERATOR_COUNT)
    , m_countY(COVERGENERATOR_COUNT)
    , m_split(Divide)
    , m_blur(0)
    , m_default(COVERGENERATOR_DEFAULT) {}

//-------------------------------------------------------------------------------------------------
// Interface
//-------------------------------------------------------------------------------------------------

void CoverGenerator::setSize(const QSize & size)
{
    m_size = size;
}

void CoverGenerator::setCountX(int x)
{
    m_countX = x;
}

void CoverGenerator::setCountY(int y)
{
    m_countY = y;
}

void CoverGenerator::setSplit(Split split)
{
    m_split = split;
}

void CoverGenerator::setBlur(int radius)
{
    m_blur = radius;
}

void CoverGenerator::setDefaultThumbnail(const QString & fileName)
{
    m_default = fileName;
}

int CoverGenerator::requiredNoOfThumbnails() const
{
    return m_countX * m_countY;
}

//-------------------------------------------------------------------------------------------------
// QRunnable implementation
//-------------------------------------------------------------------------------------------------

QImage CoverGenerator::execute(QStringList thumbnails) const
{
    int count = m_countX * m_countY;

    int countX;
    int countY;

    if (thumbnails.isEmpty())
    {
        if (m_split == CoverGenerator::Duplicate)
        {
            while (thumbnails.count() != count)
            {
                thumbnails.append(m_default);
            }

            countX = m_countX;
            countY = m_countY;
        }
        else
        {
            thumbnails.append(m_default);

            countX = 1;
            countY = 1;
        }
    }
    else if (m_split == CoverGenerator::Duplicate)
    {
        int index = 0;

        while (thumbnails.count() != count)
        {
            thumbnails.append(thumbnails.at(index));

            index++;
        }

        countX = m_countX;
        countY = m_countY;
    }
    else // if (m_split == CoverGenerator::Divide)
    {
        countX = m_countX;

        // NOTE: We try to divide thumbnails as far as we can based on their total count.
        countY = std::ceil((qreal) thumbnails.count() / m_countX);
    }

    QImage image(m_size, QImage::Format_RGB32);

    image.fill(Qt::white);

    QPainter painter;

    painter.begin(&image);

    draw(painter, thumbnails, countX, countY);

    painter.end();

    if (m_blur > 0)
        blur(image);

    return image;
}

//-------------------------------------------------------------------------------------------------
// Private functions
//-------------------------------------------------------------------------------------------------

void CoverGenerator::draw(QPainter & painter,
                          const QStringList & fileNames, int countX, int countY) const
{
    int count = fileNames.count();

    const int width  = std::ceil(m_size.width()  / static_cast<double>(countX));
    const int height = std::ceil(m_size.height() / static_cast<double>(countY));

    for (int y = 0; y < countY; y++)
    {
        for (int x = 0; x < countX; x++)
        {
            int index = countX * y + x;

            if (index == count) return;

            QRect rect;

            // NOTE: This handles the wider thumbnail case (e.g. for a 2x1 grid).
            if (index == count - 1 && x != countX - 1)
            {
                rect = QRect(width * x, height * y, width * countX - x, height);
            }
            else
                rect = QRect(width * x, height * y, width, height);

            QString fileName = fileNames.at(index);

            if (fileName.isEmpty())
                drawImage(painter, m_default, rect);
            else
                drawImage(painter, fileName, rect);
        }
    }
}

void CoverGenerator::drawImage(QPainter & painter, const QString & fileName, const QRect & target) const
{
    //QFile expect the :/ instead of qrc:// for resources files
    const QUrl fileURL {fileName};
    const QString adaptedFilename = QQmlFile::urlToLocalFileOrQrc(fileURL);
    QFile file(adaptedFilename.isEmpty() ? fileName : adaptedFilename);

    if (file.open(QIODevice::ReadOnly) == false)
    {
        // NOTE: This image does not seem valid so we paint the placeholder instead.
        if (fileName != m_default)
            drawImage(painter, m_default, target);

        return;
    }

    QImageReader reader(&file);

    if (reader.canRead() == false)
        return;

    QSize size = reader.size().scaled(target.width(),
                                      target.height(), Qt::KeepAspectRatioByExpanding);

    QImage image;

    // NOTE: QImage::scaled provides a better quality compared to QImageReader::setScaledSize.
    //       Except for svg(s).
    if (fileName.endsWith(".svg", Qt::CaseInsensitive))
    {
        if (size.isEmpty() == false)
        {
            reader.setScaledSize(size);
        }

        if (reader.read(&image) == false)
            return;
    }
    else
    {
        if (reader.read(&image) == false)
            return;

        if (size.isEmpty() == false)
        {
            // NOTE: We are using Qt::SmoothTransformation to favor quality.
            image = image.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        }
    }

    int x = std::ceil((image.width() - target.width()) / 2.);
    int y = std::ceil((image.height() - target.height()) / 2.);

    QRect source(x, y, target.width(), target.height());

    painter.drawImage(target, image, source);
}

//-------------------------------------------------------------------------------------------------

void CoverGenerator::blur(QImage& image) const
{
    if (Q_LIKELY(&qt_blurImage))
    {
        // A symbol is available for qt_blurImage()
        // Exported function can be used directly within a separate thread:
        qt_blurImage(image, 2.5 * (m_blur + 1), true);
    }
    else
    {
        const auto blurImage = [&]() {
            QGraphicsScene scene;

            QGraphicsPixmapItem item(QPixmap::fromImage(image));

            QGraphicsBlurEffect effect;

            effect.setBlurRadius(m_blur);

            effect.setBlurHints(QGraphicsBlurEffect::QualityHint);

            item.setGraphicsEffect(&effect);

            scene.addItem(&item);

            QPainter painter(&image);

            scene.render(&painter);
        };

        if (qApp->thread() == QThread::currentThread())
        {
            blurImage();
        }
        else
        {
            // Not executing in Qt GUI thread, this is not supported.
            // Block this thread, and blur the image in the GUI thread instead:
            QMetaObject::invokeMethod(qApp, blurImage, Qt::BlockingQueuedConnection);
        }
    }
}

//-------------------------------------------------------------------------------------------------

QString CoverGenerator::getPrefix(vlc_ml_parent_type type) const
{
    switch (type)
    {
        case VLC_ML_PARENT_GENRE:
            return "genre";
        case VLC_ML_PARENT_GROUP:
            return "group";
        case VLC_ML_PARENT_FOLDER:
            return "folder";
        case VLC_ML_PARENT_PLAYLIST:
            return "playlist";
        default:
            return "unknown";
    }
}

Messung
CHZG
85989994

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.