/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>.
 *
 * Authors: hxf <hewenfei@kylinos.cn>
 *
 */

/*!
    \qmltype Icon
    \inqmlmodule org.ukui.quick.items
    \ingroup ukui-quick-items
    \brief 提供高级图标显示组件。

    Icon是一个功能强大的图标组件，继承自QQuickItem，使用场景图（Scene Graph）进行渲染。
    相比ThemeIcon，Icon提供了更多高级功能，包括：
    \list
        \li 支持多种图标源类型（主题图标、文件路径、QIcon、QPixmap等）
        \li 支持图标模式（正常、高亮、自动高亮、禁用等）
        \li 支持强制圆形显示
        \li 支持应用图标代理，自动处理应用图标
        \li 支持为第三方图标添加统一底板
        \li 自动识别图标类型并进行优化处理
    \endlist

    \section1 使用示例

    基本用法：
    \qml
    import org.ukui.quick.items 1.0

    Icon {
        width: 64
        height: 64
        source: "application-name"
        mode: Icon.AutoHighlight
        radius: 8
    }
    \endqml

    \sa ThemeIcon
*/

/*!   \qmlproperty enumeration Icon::Mode
    \brief 图标显示模式枚举。

    可选值：
    \list
        \li Icon.Normal - 正常模式
        \li Icon.Highlight - 高亮模式
        \li Icon.AutoHighlight - 自动高亮模式，根据主题自动切换
        \li Icon.ForceHighlight - 强制高亮模式
        \li Icon.Disabled - 禁用模式，显示为灰色
    \endlist
*/

/*!
    \qmlproperty Icon::Mode Icon::mode
    \brief 图标的显示模式。

    设置图标的显示模式，支持正常、高亮、自动高亮、强制高亮和禁用等模式。
*/

/*!
    \qmlproperty var Icon::source
    \brief 图标源。

    可以是主题图标名称、文件路径、QIcon、QPixmap、QImage或QBitmap。
*/

/*!
    \qmlproperty var Icon::fallbackSource
    \brief 备用图标源。

    当主图标源无法加载时使用的备用图标。
*/

/*!
    \qmlproperty int Icon::radius
    \brief 图标的圆角半径。

    设置图标的圆角半径，单位为像素。
*/

/*!
    \qmlproperty bool Icon::forceRound
    \brief 是否强制显示为圆形。

    当设置为true时，图标将被裁剪为圆形。
*/

/*!
    \qmlproperty enumeration Icon::highlightColor
    \brief 高亮时的颜色角色。

    设置图标高亮时使用的主题颜色角色，可选值请参阅Theme::ColorRole。
*/

/*!
    \qmlproperty GradientColor* Icon::dtThemeHighlightColor
    \brief DT主题高亮颜色。

    设置DT主题系统的高亮颜色对象。如果未设置，将使用系统默认高亮颜色。
*/

/*!
    \qmlproperty ApplicationIconProxy* Icon::proxy
    \brief 应用图标代理。

    \readonly

    返回应用图标代理对象，用于处理应用图标的特殊逻辑。
*/

/*!
    \qmlproperty bool Icon::addUnifiedIconBox
    \brief 是否为第三方图标添加统一底板。

    \list
        \li true - 为第三方图标添加统一背景底板
        \li false - 不添加统一底板
    \endlist

    默认值为false。
*/

#include "icon.h"
#include "icon-helper.h"
#include "icon-provider.h"
#include "theme-icon.h"

#include <QHash>
#include <QIcon>
#include <QImage>
#include <QBitmap>
#include <QPainter>
#include <QPainterPath>
#include <QtMath>
#include <QSGTexture>
#include <QSGImageNode>
#include <QQuickWindow>
#include <algorithm>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <mutex>

namespace UkuiQuick {
class IconBackgroundUtils;
static IconBackgroundUtils *g_iconBackgroundUtils = nullptr;
static std::once_flag onceFlag;
#define COLOR_DIFFERENCE 15
class IconBackgroundUtils
{
public:
    static IconBackgroundUtils* instance();
    void setIconThemeName(const QString& iconThemeName);
    bool isValid() const;
    QIcon iconBackground();
    QIcon iconBackgroundWithoutShadow();
    bool containShadow(uint size) const;
    qreal offsetX(uint size) const;
    qreal offsetY(uint size) const;
    QVarLengthArray<qreal, 256> outLineDistance(uint width);
    qreal centerAreaRate() const;
private:
    IconBackgroundUtils();
    void updateIconBackConfig();
    void updateParam();
    void reset();
    QMap<uint, bool> m_containShadow;    //当前图标主题第三方图标统一背景图是否包含阴影
    QMap<uint, qreal> m_offsetX;               //当前图标主题第三方图标统一背景图X轴偏移量系数
    QMap<uint, qreal> m_offsetY;               //当前图标主题第三方图标统一背景图Y轴偏移量系数
    qreal m_centerAreaRate = 0.625;         //当前图标主题视觉中心区域占背景图总大小比值
    QJsonObject m_config;
    QString m_themeName;
    QIcon m_background = QIcon::fromTheme(QStringLiteral("icon-background"));
    QIcon m_backgroundWithoutShadow = QIcon::fromTheme(QStringLiteral("icon-background-noshadow"));
    QMap<uint, QVarLengthArray<qreal, 256>> m_outLineDistance;   //当前图标主题第三方图标统一背景图外边框轮廓
    bool m_valid = false;
};

IconBackgroundUtils* IconBackgroundUtils::instance()
{
    std::call_once(onceFlag, [ & ] {
        g_iconBackgroundUtils = new IconBackgroundUtils();
    });
    return g_iconBackgroundUtils;
}

void IconBackgroundUtils::setIconThemeName(const QString &iconThemeName)
{
    if (iconThemeName == m_themeName) {
        return;
    }
    m_themeName = iconThemeName;
    updateParam();
}

bool IconBackgroundUtils::isValid() const
{
    return m_valid;
}

void IconBackgroundUtils::updateIconBackConfig()
{
    QFile file("/usr/share/ukui/ukui-quick-items/iconThemeBackgroundConfig.json");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "IconBackgroundUtils::updateIconBackConfig() failed to open config file" << file.errorString();
        return;
    }
    QTextStream iStream(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    iStream.setCodec("UTF-8");
#else
    iStream.setEncoding(QStringConverter::Utf8);
#endif

    QJsonParseError parseError {};
    QJsonDocument document = QJsonDocument::fromJson(iStream.readAll().toUtf8(), &parseError);
    file.close();

    if (parseError.error != QJsonParseError::NoError) {
        qWarning() << "IconBackgroundUtils::updateIconBackConfig() failed to parse config file" << parseError.errorString();
        return;
    }

    if (!document.isObject()) {
        qWarning() << "IconBackgroundUtils::updateIconBackConfig() failed to parse config file: Is not object.";
        return;
    }
    m_config = document.object();
}

void IconBackgroundUtils::updateParam()
{
    if (m_background.isNull() || m_background.name() != QStringLiteral("icon-background")
        || m_backgroundWithoutShadow.isNull() || m_backgroundWithoutShadow.name() != QStringLiteral("icon-background-noshadow")) {
        qWarning() << "IconBackgroundUtils::updateParam() failed to get icon background, background or icon background without shadow is null.";
        reset();
        return;
    }
    auto currentThemeConfig = m_config.value(m_themeName).toObject();
    if (currentThemeConfig.isEmpty()) {
        qWarning() << "IconBackgroundUtils::updateParam() failed to get theme config: theme config is empty.";
        reset();
        return;
    }
    m_centerAreaRate = currentThemeConfig.value("centerAreaRate").toDouble();

    QStringList sizeList = {"16", "24", "32", "48", "64", "96", "128", "512"};
    for(auto size : sizeList) {
        auto sizeObject = currentThemeConfig.value(size).toObject();
        if (sizeObject.isEmpty()) {
            qWarning() << QString("IconBackgroundUtils::updateParam() failed to get theme config: size = %1 config is empty.").arg(size);
            reset();
            return;
        }
        qreal offsetX = sizeObject.contains("offsetX") ? sizeObject.value("offsetX").toDouble() : currentThemeConfig.value("offsetX").toDouble();
        qreal offsetY = sizeObject.contains("offsetY") ? sizeObject.value("offsetY").toDouble() : currentThemeConfig.value("offsetY").toDouble();
        m_offsetX.insert(size.toUInt(), offsetX);
        m_offsetY.insert(size.toUInt(), offsetY);

        bool containShadow = sizeObject.contains("containShadow") ? sizeObject.value("containShadow").toBool() : currentThemeConfig.value("containShadow").toBool();
        m_containShadow.insert(size.toUInt(), containShadow);
        auto distanceArr = sizeObject.value("outLineDistance").toArray();
        if(distanceArr.size() != 256) {
            qWarning() << QString("IconBackgroundUtils::updateParam() failed to get theme config: %1 outLineDistance size = %2 is invalid.").arg(m_themeName, size);
            reset();
            return;
        }
        QVarLengthArray<qreal, 256> distance;
        for (auto val : distanceArr) {
            distance.append(val.toVariant().toReal());
        }
        m_outLineDistance.insert(size.toUInt(), distance);
    }
    m_valid = true;
}

void IconBackgroundUtils::reset()
{
    m_valid = false;
    m_containShadow.clear();
    m_offsetX.clear();
    m_offsetY.clear();
    m_outLineDistance.clear();
}

QIcon IconBackgroundUtils::iconBackground()
{
    return m_background;
}

QIcon IconBackgroundUtils::iconBackgroundWithoutShadow()
{
    return m_backgroundWithoutShadow;
}

bool IconBackgroundUtils::containShadow(uint size) const
{
    if (m_backgroundWithoutShadow.availableSizes().contains(QSize(size, size)) || m_backgroundWithoutShadow.actualSize(QSize(size, size)) != QSize(size, size)) {
        if (size <= 16) {
            return m_containShadow.value(16);
        } else if (size <= 24) {
            return m_containShadow.value(24);
        } else if (size <= 32) {
            return m_containShadow.value(32);
        } else if (size <= 48) {
            return m_containShadow.value(48);
        } else if (size <= 64) {
            return m_containShadow.value(64);
        } else if (size <= 96) {
            return m_containShadow.value(96);
        }
    }
    return m_containShadow.value(128);
}

qreal IconBackgroundUtils::offsetX(uint size) const
{
    if (m_backgroundWithoutShadow.availableSizes().contains(QSize(size, size)) || m_backgroundWithoutShadow.actualSize(QSize(size, size)) != QSize(size, size)) {
        if (size <= 16) {
            return m_offsetX.value(16);
        } else if (size <= 24) {
            return m_offsetX.value(24);
        } else if (size <= 32) {
            return m_offsetX.value(32);
        } else if (size <= 48) {
            return m_offsetX.value(48);
        } else if (size <= 64) {
            return m_offsetX.value(64);
        } else if (size <= 96) {
            return m_offsetX.value(96);
        }
    }
    return m_offsetX.value(128);
}

qreal IconBackgroundUtils::offsetY(uint size) const
{
    if (m_backgroundWithoutShadow.availableSizes().contains(QSize(size, size)) || m_backgroundWithoutShadow.actualSize(QSize(size, size)) != QSize(size, size)) {
        if (size <= 16) {
            return m_offsetY.value(16);
        } else if (size <= 24) {
            return m_offsetY.value(24);
        } else if (size <= 32) {
            return m_offsetY.value(32);
        } else if (size <= 48) {
            return m_offsetY.value(48);
        } else if (size <= 64) {
            return m_offsetY.value(64);
        } else if (size <= 96) {
            return m_offsetY.value(96);
        }
    }
    return m_offsetY.value(128);
}

QVarLengthArray<qreal, 256> IconBackgroundUtils::outLineDistance(uint size)
{
    if (size <= 20) {
        return m_outLineDistance.value(16);
    } else if (size > 20 && size <= 28) {
        return m_outLineDistance.value(24);
    } else if (size > 28 && size <= 40) {
        return m_outLineDistance.value(32);
    } else if (size > 40 && size <= 56) {
        return m_outLineDistance.value(48);
    } else if (size > 56 && size <= 80) {
        return m_outLineDistance.value(64);
    } else if (size <= 96) {
        return m_outLineDistance.value(96);
    } else if (size == 512) {
        return m_outLineDistance.value(512);
    }
    return m_outLineDistance.value(128);
}

qreal IconBackgroundUtils::centerAreaRate() const
{
    return m_centerAreaRate;
}

IconBackgroundUtils::IconBackgroundUtils()
{
    updateIconBackConfig();
    // QObject::connect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::iconThemeNameChanged, [this]() {
    //     setIconThemeName(ThemeGlobalConfig::instance()->iconThemeName());
    // });
}

class IconPrivate
{
public:
    int radius {0};
    bool forceRound {false};
    bool textureChanged {true};
    QIcon icon;
    QVariant fallbackSource;
    QIcon fallbackIcon;
    bool fallbackIconLoaded {false};
    Icon::Mode mode {Icon::Normal};
    QString          pointText {""};
    Types::Pos    pointPos {Types::TopRight};
    Icon::PointType  pointType {Icon::Null};
    Theme::ColorRole pointColor {Theme::Highlight};
    Theme::ColorRole highlightColor {Theme::HighlightedText};
    GradientColor* dtThemeHighlightColor = nullptr;
    std::shared_ptr<QSGTexture> currentTexture;
    static QHash<QQuickWindow*, QHash<qint64, std::weak_ptr<QSGTexture> > > textureCache;
    ApplicationIconProxy* proxy = nullptr;
    bool addUnifiedIconBox {false};
    //图标类型
    Icon::ImageType imageType = {Icon::Uninitialized};
    QImage imageCache;
    static const QColor symbolicColor;
};

const QColor IconPrivate::symbolicColor = QColor(26, 26, 26);
QHash<QQuickWindow*, QHash<qint64, std::weak_ptr<QSGTexture> > > IconPrivate::textureCache = {};
// ===== ICON ====== //
Icon::Icon(QQuickItem *parent) : QQuickItem(parent), d(new IconPrivate)
{
    setFlag(QQuickItem::ItemHasContents);
    connect(this, &QQuickItem::widthChanged, this, &Icon::onSizeChanged);
    connect(this, &QQuickItem::heightChanged, this, &Icon::onSizeChanged);
}

Icon::~Icon()
{
    if (d) {
        delete d;
        d = nullptr;
    }
}

// ====== DRAW ====== //
QSGNode *Icon::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data)
{
    QSGImageNode *imageNode = nullptr;
    if (node) {
        imageNode = static_cast<QSGImageNode *>(node);
    } else {
        imageNode = window()->createImageNode();
        imageNode->setOwnsTexture(true);
        imageNode->setFiltering(QSGTexture::Linear);
        node = imageNode;
    }

    if (d->textureChanged) {
        imageNode->setTexture(createTexture());
        imageNode->setSourceRect({QPoint(0, 0), imageNode->texture()->textureSize()});
        d->textureChanged = false;
    }

    imageNode->setRect(boundingRect());
    return node;
}

QSGTexture *Icon::createTexture()
{
    QImage image;
    // 获取原始图像
    if (d->icon.isNull()) {
        image = loadFallbackIcon();
    } else {
        if (d->forceRound) {
            // 处理圆形图标
            QSize rawSize = size().toSize();
            if (!d->icon.availableSizes().isEmpty()) {
                auto sizes = d->icon.availableSizes();
                rawSize = *std::max_element(sizes.begin(), sizes.end(),
                                                  [](const QSize&a, const QSize&b) {
                                                      return a.width() < b.width();
                                                  });
            }

            QPixmap rawPixmap = d->icon.pixmap(rawSize);

            int diameter = std::min(rawPixmap.height(), rawPixmap.width());
            QPixmap pixmap(diameter, diameter);
            pixmap.fill(Qt::transparent);
            QPainter painter(&pixmap);
            painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
            QPainterPath path;
            path.addEllipse(0, 0, diameter, diameter);
            painter.setClipPath(path);

            QRect targetRect, sourceRect;
            targetRect = QRect(0, 0, diameter, diameter);
            if (rawPixmap.width() > rawPixmap.height()) {
                sourceRect = QRect((rawPixmap.width() - diameter) / 2, 0, diameter, diameter);
            } else {
                sourceRect = QRect(0, (rawPixmap.height() - diameter) / 2, diameter, diameter);
            }
            painter.drawPixmap(targetRect, rawPixmap, sourceRect);
            image = pixmap.toImage().scaled(size().toSize() * window()->devicePixelRatio(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        } else {
            image = d->icon.pixmap(size().toSize()).toImage();
            if (d->addUnifiedIconBox && IconBackgroundUtils::instance()->isValid()) {
                image = addIconBox(image);
            }
            if(image.isNull()) {
                qWarning() << "Icon::createTexture : Can't load icon with size " << size().toSize() * window()->devicePixelRatio();
                image = loadFallbackIcon();
            }
        }
    }

//    // 缩放大图像？
//    QSize imageSize = image.size();
//    if (imageSize.width() > 512 || imageSize.height() > 512) {
//        image.scaled();
//        imageSize = image.size();
//    }

    // 修改图像
    //imageCorrection(image);
    if (d->mode & Icon::Disabled) {
        // use style
        image = QIcon(QPixmap::fromImage(std::move(image))).pixmap(size().toSize(), QIcon::Disabled).toImage();
    }
    else if (d->mode & Icon::Highlight) {
        bool isPureColor = true;
        if(image.format() != QImage::Format_ARGB32) {
            image = image.convertToFormat(QImage::Format_ARGB32);
        }
        if (!d->mode.testFlag(Icon::ForceHighlight)) {
            // TODO: 更新判断纯色算法
            isPureColor = isImagePureColor(image);
        }
        GradientColor* highlightColor = d->dtThemeHighlightColor
                                            ? d->dtThemeHighlightColor
                                            : DtTheme::self(qmlEngine(this))->highlightedTextActive();
        if (isPureColor) {
            QPainter p(&image);
            p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
            p.setCompositionMode(QPainter::CompositionMode_SourceIn);
            if (highlightColor->colorType() == DtColorType::Type::Pure) {
                p.fillRect(image.rect(), highlightColor->pureColor());
            } else {
                //设置渐变色的方向
                QLinearGradient linearGradient(
                    highlightColor->getGradientStartPoint(highlightColor->gradientDeg(), image.width(), image.height())
                    , highlightColor->getGradientEndPoint(highlightColor->gradientDeg(), image.width(),
                                                          image.height()));
                //设置渐变色颜色
                linearGradient.setColorAt(
                    0.0, highlightColor->mixBackGroundColor(highlightColor->gradientStart(),
                                                            highlightColor->gradientBackground(), 1));
                linearGradient.setColorAt(
                    1.0, highlightColor->mixBackGroundColor(highlightColor->gradientEnd(),
                                                            highlightColor->gradientBackground(), 1));
                QBrush brush(linearGradient);
                p.fillRect(image.rect(), brush);
            }
        } else {
            int symbolicRed = d->symbolicColor.red();
            int symbolicGreen = d->symbolicColor.green();
            int symbolicBlue = d->symbolicColor.blue();
            if (highlightColor->colorType() == DtColorType::Type::Pure) {
                QColor baseColor = highlightColor->pureColor();
                uchar *pixels = image.bits();
                int bytesPerLine = image.bytesPerLine();
                for (int y = 0; y < image.height(); y++) {
                    QRgb* line = reinterpret_cast<QRgb*>(pixels + y * bytesPerLine);
                    for (int x = 0; x < image.width(); x++) {
                        QRgb &color = line[x];
                        if (qAlpha(color) > 0.3 * 256) {
                            if (qAbs(qRed(color) - symbolicRed) < COLOR_DIFFERENCE && qAbs(qGreen(color) - symbolicGreen) < COLOR_DIFFERENCE
                                    && qAbs(qBlue(color) - symbolicBlue) < COLOR_DIFFERENCE) {
                                color = qRgba(baseColor.red(),baseColor.green(),baseColor.blue(), qAlpha(color));
                            }
                        }
                    }
                }
            } else {
                QImage gradientImg(image.width(), image.height(), QImage::Format::Format_ARGB32);
                //设置渐变色的方向
                QLinearGradient linearGradient(
                    highlightColor->getGradientStartPoint(highlightColor->gradientDeg(), image.width(), image.height())
                    , highlightColor->getGradientEndPoint(highlightColor->gradientDeg(), image.width(),
                                                          image.height()));
                //设置渐变色颜色
                linearGradient.setColorAt(
                    0.0, highlightColor->mixBackGroundColor(highlightColor->gradientStart(),
                                                            highlightColor->gradientBackground(), 1));
                linearGradient.setColorAt(
                    1.0, highlightColor->mixBackGroundColor(highlightColor->gradientEnd(),
                                                            highlightColor->gradientBackground(), 1));
                QBrush brush(linearGradient);
                //将渐变色绘制到与图标相同大小的image上
                QPainter painterImg(&gradientImg);
                painterImg.setBrush(brush);
                painterImg.drawRect(gradientImg.rect());
                painterImg.end();

                uchar *pixels = image.bits();
                const uchar *gradientPixels = gradientImg.constBits();
                int bytesPerLine = image.bytesPerLine();
                int bytesPerLineGra = gradientImg.bytesPerLine();
                for (int y = 0; y < image.height(); y++) {
                    QRgb* line = reinterpret_cast<QRgb*>(pixels + y * bytesPerLine);
                    const QRgb* gradientLine = reinterpret_cast<const QRgb*>(gradientPixels + y * bytesPerLineGra);
                    for (int x = 0; x < image.width(); x++) {
                        QRgb &color = line[x];
                        if (qAlpha(color) > 0.3 * 256) {
                            if (qAbs(qRed(color) - symbolicRed) < COLOR_DIFFERENCE && qAbs(qGreen(color) - symbolicGreen) < COLOR_DIFFERENCE
                                    && qAbs(qBlue(color) - symbolicBlue) < COLOR_DIFFERENCE) {
                                color = qRgba(qRed(gradientLine[x]), qGreen(gradientLine[x]), qBlue(gradientLine[x]), qAlpha(color));
                            }
                        }
                    }
                }
            }
        }
    }



    //std::shared_ptr<QSGTexture> texturePtr;
    //qint64 cacheKey = image.cacheKey();
    //auto hash = IconPrivate::textureCache[window()];
    //if (hash.contains(cacheKey)) {
    //    texturePtr = hash[cacheKey].lock();
    //    if (texturePtr) {
    //        d->currentTexture = texturePtr;
    //        return d->currentTexture.get();
    //    }
    //}

    QSGTexture *texture = window()->createTextureFromImage(image);
    //texturePtr = std::shared_ptr<QSGTexture>(texture, [this] (QSGTexture *texture) {
    //    //hash.remove(cacheKey);
    //    //if (hash.isEmpty()) {
    //    //    IconPrivate::textureCache.remove(window());
    //    //}
    //
    //    delete texture;
    //});

    //hash[cacheKey] = texturePtr;
    //d->currentTexture = texturePtr;
    return texture;
}

void Icon::imageCorrection(QImage &image)
{
    // 画点
    drawPoint(image);
    // 修改状态
}

QPoint Icon::posPoint(const QSize &imageSize, const QSize &pointSize) const
{
    QPoint point;
    switch (d->pointPos) {
        default:
        case Types::TopRight:
            point = {imageSize.width() - pointSize.width(), 0};
            break;
        case Types::TopLeft:
            point = {0, 0};
            break;
        case Types::BottomRight:
            point = {imageSize.width() - pointSize.width(), imageSize.height() - pointSize.height()};
            break;
        case Types::BottomLeft:
            point = {0, imageSize.height() - pointSize.height()};
            break;
        case Types::Center:
            point = {(imageSize.width() - pointSize.width()) / 2, (imageSize.height() - pointSize.height()) / 2};
            break;
        case Types::LeftCenter:
            point = {0, (imageSize.height() - pointSize.height()) / 2};
            break;
        case Types::TopCenter:
            point = {(imageSize.width() - pointSize.width()) / 2, 0};
            break;
        case Types::RightCenter:
            point = {imageSize.width() - pointSize.width(), (imageSize.height() - pointSize.height()) / 2};
            break;
        case Types::BottomCenter:
            point = {(imageSize.width() - pointSize.width()) / 2, imageSize.height() - pointSize.height()};
            break;
    }

    if (point.x() < 0) {
        point.setX(0);
    } else if ((point.x() + pointSize.width()) > imageSize.width()) {
        point.setX(imageSize.width() - pointSize.width());
    }

    if (point.y() < 0) {
        point.setY(0);
    } else if ((point.y() + pointSize.height()) > imageSize.height()) {
        point.setY(imageSize.height() - pointSize.height());
    }

    return point;
}

void Icon::drawPoint(QImage &image)
{
    if (d->pointType == Icon::Null) {
        return;
    }

    QPainter painter(&image);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setBrush(Theme::instance()->color(d->pointColor));
    painter.setPen(Theme::instance()->color(d->pointColor));

    if (d->pointType == Icon::Point) {
        QSize pointSize(qFloor(image.width() * 0.35), qFloor(image.height() * 0.35));
        QRect rect(posPoint(image.size(), pointSize), pointSize);

        painter.drawEllipse(rect);

    } else if (d->pointType == Icon::Text) {
        QRect rect = {0, 0, qFloor(image.width() * 0.4), qFloor(image.height() * 0.4)};

        QFont font = painter.font();
        // 为了将两位数正常显示在框框中
        font.setPointSize(qFloor(6.0 * rect.width() / 12.0));
        font.setBold(true);

        QString text = d->pointText;
        QFontMetrics fontMetrics(font);
        QRect textRect = fontMetrics.boundingRect(rect, Qt::AlignVCenter | Qt::AlignHCenter, text);
        if (textRect.width() > rect.width()) {
            if (textRect.width() > image.width()) {
                rect.setWidth(image.width());
                text = fontMetrics.elidedText(text, Qt::ElideRight, rect.width() - 4);
            } else {
                rect.setWidth(textRect.width() + 8);
            }
        }

        rect.moveTopLeft(posPoint(image.size(), rect.size()));

        // 底部圆
        painter.save();
        painter.setPen(Theme::instance()->colorWithCustomTransparency(Theme::BrightText, Theme::Active, 0.15));
        painter.drawRoundedRect(rect, qFloor(rect.height() * 0.5), qFloor(rect.height() * 0.5));
        painter.restore();

        // draw text.
        painter.save();
        // TODO: 优化字体显示
        painter.setFont(font);
        painter.setPen(Theme::instance()->buttonText());
        painter.drawText(rect, Qt::AlignVCenter | Qt::AlignHCenter, text);
        painter.restore();
    }
}

void Icon::onSizeChanged()
{
    markTextureChanged();
}

// ====== METHODS ====== //
QVariant Icon::source() const
{
    return d->icon;
}

void Icon::setSource(const QVariant &source)
{
    if (d->proxy && !d->proxy->icon().isEmpty()) {
        qInfo() << "This icon has been set a effective proxy, you can not set source explicitly."
                << "source attempted to set:" << source
                << "proxy icon:" << d->proxy->icon();
        return;
    }

    bool applyIcon = applyVariantToIcon(source, d->icon);

    if (applyIcon) {
        markTextureChanged();
        Q_EMIT sourceChanged();
    }
}

QVariant Icon::fallbackSource() const
{
    return d->fallbackSource;
}

void Icon::setFallbackSource(const QVariant &fallback)
{
    if(d->fallbackSource != fallback) {
        d->fallbackSource = fallback;
        d->fallbackIcon = QIcon();
        d->fallbackIconLoaded = false;
        markTextureChanged();
    }
}

bool Icon::applyVariantToIcon(const QVariant &source, QIcon &icon)
{
    switch (source.userType()) {
    case QMetaType::QIcon:
        icon = source.value<QIcon>();
        break;
    case QMetaType::QImage:
        icon.addPixmap(QPixmap::fromImage(source.value<QImage>()));
        break;
    case QMetaType::QPixmap:
        icon.addPixmap(source.value<QPixmap>());
        break;
    case QMetaType::QBitmap:
        icon.addPixmap(source.value<QBitmap>());
        break;
    case QMetaType::QString: {
        icon = IconHelper::loadIcon(source.value<QString>());
        break;
    }
    default:
        break;
    }

    return !icon.isNull();
}

QImage Icon::loadFallbackIcon()
{
    if (d->fallbackSource.isNull()) {
        qWarning() << "Icon::loadFallbackIcon : fallback icon is Null";
        QPixmap pixmap(size().toSize() * window()->devicePixelRatio());
        pixmap.fill(Qt::transparent);
        return pixmap.toImage();
    }
    if (!d->fallbackIconLoaded) {
        applyVariantToIcon(d->fallbackSource, d->fallbackIcon);
        d->fallbackIconLoaded = true;
    }
    if (!d->fallbackIcon.isNull()) {
        return d->fallbackIcon.pixmap(size().toSize() * window()->devicePixelRatio()).toImage();
    }

    qWarning() << "Icon::loadFallbackIcon : failed to load fallback icon from" << d->fallbackSource;
    QPixmap pixmap(size().toSize() * window()->devicePixelRatio());
    pixmap.fill(Qt::transparent);
    return pixmap.toImage();
}

bool Icon::forceRound() const
{
    return d->forceRound;
}

void Icon::setForceRound(bool forceRound)
{
    if (d->forceRound == forceRound) {
        return;
    }

    d->forceRound = forceRound;
    markTextureChanged();
    Q_EMIT forceRoundChanged();
}

Icon::Mode Icon::mode() const
{
    return d->mode;
}

void Icon::setMode(const Icon::Mode &mode)
{
    if (d->mode == mode) {
        return;
    }

    d->mode = mode;
    if (d->mode & Icon::AutoHighlight) {
        updateMode();
        connect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::styleColorChanged, this, &Icon::updateMode, Qt::UniqueConnection);
        connect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::themeNameChanged, this, &Icon::updateMode, Qt::UniqueConnection);
    } else {
        disconnect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::styleColorChanged, this, &Icon::updateMode);
        disconnect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::themeNameChanged, this, &Icon::updateMode);
        markTextureChanged();
    }

    Q_EMIT modeChanged();
}

Theme::ColorRole Icon::highlightColor() const
{
    return d->highlightColor;
}

void Icon::setHighlightColor(const Theme::ColorRole &color)
{
    if (d->highlightColor == color) {
        return;
    }

    d->highlightColor = color;
    markTextureChanged();
    Q_EMIT highlightColorChanged();
}

GradientColor* Icon::dtThemeHighlightColor() const
{
    return d->dtThemeHighlightColor;
}

void Icon::setDtThemeHighlightColor(GradientColor *color)
{
    if(d->dtThemeHighlightColor == nullptr && isComponentComplete()) {
        disconnect(DtTheme::self(qmlEngine(this)), &DtTheme::highlightedTextActiveChanged, this, &Icon::markTextureChanged);
    }
    if(color != nullptr && d->dtThemeHighlightColor != color) {
        d->dtThemeHighlightColor = color;
        markTextureChanged();
        Q_EMIT dtThemeHighlightColorChanged();
    }
}

int Icon::radius() const
{
    return d->radius;
}

void Icon::setRadius(int radius)
{
    if (d->radius == radius) {
        return;
    }

    d->radius = radius;
    markTextureChanged();
    Q_EMIT radiusChanged();
}

Icon::PointType Icon::pointType() const
{
    return d->pointType;
}

void Icon::setPointType(Icon::PointType type)
{
    if (d->pointType == type) {
        return;
    }

    d->pointType = type;
    markTextureChanged();
    Q_EMIT pointTypeChanged();
}

Theme::ColorRole Icon::pointColor() const
{
    return d->pointColor;
}

void Icon::setPointColor(const Theme::ColorRole &color)
{
    if (d->pointColor == color) {
        return;
    }

    d->pointColor = color;
    markTextureChanged();
    Q_EMIT pointColorChanged();
}

QString Icon::pointText() const
{
    return d->pointText;
}

void Icon::setPointText(const QString &text)
{
    if (d->pointText == text) {
        return;
    }

    d->pointText = text;
    markTextureChanged();
    Q_EMIT pointTextChanged();
}

Types::Pos Icon::pointPos() const
{
    return d->pointPos;
}

void Icon::setPointPos(Types::Pos pos)
{
    if (d->pointPos == pos) {
        return;
    }

    d->pointPos = pos;
    markTextureChanged();
    Q_EMIT pointPosChanged();
}

bool Icon::addUnifiedIconBox() const
{
    return d->addUnifiedIconBox;
}

void Icon::setAddUnifiedIconBox(bool addUnifiedIconBox)
{
    if(d->addUnifiedIconBox == addUnifiedIconBox) {
        return;
    }
    d->addUnifiedIconBox = addUnifiedIconBox;
    if (d->addUnifiedIconBox) {
        IconBackgroundUtils::instance()->setIconThemeName(ThemeGlobalConfig::instance()->iconThemeName());
        QImage().swap(d->imageCache);
    }
    markTextureChanged();
    Q_EMIT addUnifiedIconBoxChanged();
}

inline void Icon::markTextureChanged()
{
    d->textureChanged = true;
    update();
}

ApplicationIconProxy* Icon::proxy()
{
    if (d->proxy == nullptr) {
        d->proxy = new ApplicationIconProxy(this);
        updateSourceFromProxy();
        connect(d->proxy, &ApplicationIconProxy::iconChanged, this, &Icon::updateSourceFromProxy);
    }
    return d->proxy;
}

void Icon::updateMode()
{
    if (ThemeGlobalConfig::instance()->isDarkTheme()) {
        d->mode |= Icon::Highlight;
    } else {
        d->mode &= ~Icon::Highlight;
    }

    markTextureChanged();
}

void Icon::updateSourceFromProxy()
{
    if (!d->proxy->icon().isEmpty()) {
        d->icon = IconHelper::loadIcon(d->proxy->icon());
        if (!d->icon.isNull()) {
            markTextureChanged();
        }
    }
}

void Icon::onIconThemeNameChanged()
{
    if (d->addUnifiedIconBox) {
        IconBackgroundUtils::instance()->setIconThemeName(ThemeGlobalConfig::instance()->iconThemeName());
        QImage().swap(d->imageCache);
    }
    markTextureChanged();
}

void Icon::componentComplete()
{
    QQuickItem::componentComplete();
    if(d->dtThemeHighlightColor == nullptr) {
        connect(DtTheme::self(qmlEngine(this)), &DtTheme::highlightedTextActiveChanged, this, &Icon::markTextureChanged);
    }
    connect(ThemeGlobalConfig::instance(), &ThemeGlobalConfig::iconThemeNameChanged, this, &Icon::onIconThemeNameChanged);
}

void Icon::itemChange(ItemChange change, const ItemChangeData &value)
{
    if (change == ItemDevicePixelRatioHasChanged) {
        markTextureChanged();
    } else if (change == ItemSceneChange) {
        const bool attachedToScene = value.window != nullptr;
        setFlag(ItemHasContents, attachedToScene);
        d->textureChanged = true;
        if (attachedToScene) {
            update();
        }
    }
    QQuickItem::itemChange(change, value);
}

QImage Icon::addIconBox(QImage &image)
{
    if(image.isNull()) {
        return image;
    }

    QImage backImage = IconBackgroundUtils::instance()->iconBackground().pixmap(size().toSize()).toImage();
    if(backImage.isNull()) {
        return image;
    }

    QImage backImageNoShadow = IconBackgroundUtils::instance()->iconBackgroundWithoutShadow().pixmap(size().toSize()).toImage();
    QImage backImageEffectArea = getEffectiveArea(backImageNoShadow);

    //根据计算出来的非透明点找到有效区域并截取出来
    QImage effectiveArea = getEffectiveArea(image);
    if (image != d->imageCache) {
        getImageType(effectiveArea, image, backImage.width(), backImageEffectArea.width());
        d->imageCache = image;
    }
    bool cliped = false;
    switch (d->imageType) {
        //第一方图标和未定义类型图标不作处理
        case Icon::Uninitialized :
        case Icon::FirstParty : {
            return image;
        }
        //不是正方形的图标，按比例将图标有效区域缩放到视觉中心区域并居中
        case Icon::RectangleHorizontal : {
            effectiveArea = effectiveArea.scaledToWidth(backImage.width() * IconBackgroundUtils::instance()->centerAreaRate(), Qt::SmoothTransformation);
            break;
        }
        case Icon::RectangleVertical : {
            effectiveArea = effectiveArea.scaledToHeight(backImage.height() * IconBackgroundUtils::instance()->centerAreaRate(), Qt::SmoothTransformation);
            break;
        }
        //有底图标按照第一方规范裁剪圆角并缩放至背景区域大小
        case Icon::RectangleWithBack : {
            if(IconBackgroundUtils::instance()->containShadow(image.width())) {
                effectiveArea = clipBackground(effectiveArea, backImageNoShadow, backImageEffectArea.rect());
                cliped = true;
            } else {
                effectiveArea = effectiveArea.scaledToWidth(backImage.width() * backImageEffectArea.width() / backImageNoShadow.width(), Qt::SmoothTransformation);
                if(backImage.width() < 24) {
                    if(effectiveArea.format() != QImage::Format_ARGB32) {
                        effectiveArea = effectiveArea.convertToFormat(QImage::Format_ARGB32);
                    }
                    QHash<QPair<int, int>, int> imageAlphaHash = getTransparentPoint(backImageEffectArea);
                    QHash<QPair<int, int>, int>::const_iterator it;
                    for(it = imageAlphaHash.constBegin();it != imageAlphaHash.constEnd();it++) {
                        QColor color = effectiveArea.pixelColor(it.key().first, it.key().second);
                        color.setAlpha(it.value());
                        effectiveArea.setPixelColor(it.key().first, it.key().second, color);
                    }
                }
            }
            break;
        }
        //默认将图标有效区域缩减到背景图的视觉中心区域
        default:
        case Icon::Other : {
            effectiveArea = effectiveArea.scaledToWidth(backImage.width() * IconBackgroundUtils::instance()->centerAreaRate(), Qt::SmoothTransformation);
            break;
        }
    }
    qreal dpr = backImage.devicePixelRatio();
    backImage.setDevicePixelRatio(1);
    QPainter painter(&backImage);
    painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

    if (!cliped) {
        qreal offsetX = IconBackgroundUtils::instance()->offsetX(backImage.width()) * backImage.width();
        qreal offsetY = IconBackgroundUtils::instance()->offsetY(backImage.width()) * backImage.height();
        painter.translate(offsetX, offsetY);
    }

    //将处理好的图标有效区域绘制到统一背景
    painter.drawImage(QRectF(static_cast<qreal>(backImage.width() - effectiveArea.width()) / 2, static_cast<qreal>(backImage.height() - effectiveArea.height()) / 2,effectiveArea.width(), effectiveArea.height()), effectiveArea);
    painter.end();
    backImage.setDevicePixelRatio(dpr);
    return backImage;
}

QImage Icon::clipBackground(QImage &image, QImage targetImage, QRectF targetRect)
{
    image = image.scaledToWidth(targetRect.width(),Qt::SmoothTransformation);
    qreal offsetX = IconBackgroundUtils::instance()->offsetX(targetImage.width()) * targetImage.width();
    qreal offsetY = IconBackgroundUtils::instance()->offsetY(targetImage.width()) * targetImage.height();
    qreal dpr = targetImage.devicePixelRatio();
    targetImage.setDevicePixelRatio(1);
    QPainter painter(&targetImage);
    painter.translate(offsetX, offsetY);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);

    painter.drawImage(QRectF(static_cast<qreal>(targetImage.width() - image.width()) / 2, static_cast<qreal>(targetImage.height() - image.height()) / 2, image.width(), image.height()), image);
    painter.end();
    targetImage.setDevicePixelRatio(dpr);

    return targetImage;
}

bool Icon::isTransparencyBackground(QImage image)
{
    if (image.isNull()) {
        return false;
    }
    //找到图标有效区域四个定点的第一个不透明点
    QPoint topLeft;
    QPoint topRight;
    QPoint leftTop;
    QPoint leftBottom;
    QPoint rightTop;
    QPoint rightBottom;
    QPoint bottomLeft;
    QPoint bottomRight;

    bool getMax = false;
    bool getMin = false;
    for (int y = 0; y < image.height(); ++y) {
        for (int x = 0; x < image.width(); ++x) {
            if (!getMin && qAlpha(image.pixel(x, y)) > 20) {
                topLeft.setX(x);
                topLeft.setY(y);
                getMin = true;
            }
            if (!getMax && qAlpha(image.pixel(image.width() - x - 1,  y )) > 20) {
                topRight.setX(image.width() - x - 1);
                topRight.setY(y);
                getMax = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {
            break;
        }
    }
    getMax = false;
    getMin = false;
    for (int y = image.height() - 1; y > 0; --y) {
        for (int x = 0; x < image.width(); ++x) {
            if (!getMin && qAlpha(image.pixel(x, y)) > 20) {
                bottomLeft.setX(x);
                bottomLeft.setY(y);
                getMin = true;
            }
            if (!getMax && qAlpha(image.pixel(image.width() - x - 1,  y )) > 20) {
                bottomRight.setX(image.width() - x - 1);
                bottomRight.setY(y);
                getMax = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {
            break;
        }
    }

    getMax = false;
    getMin = false;
    for (int x = 0; x < image.width(); ++x) {
        for (int y = 0; y < image.height(); ++y) {
            if (!getMin && qAlpha(image.pixel(x, y)) > 20) {
                leftTop.setX(x);
                leftTop.setY(y);
                getMin = true;
            }
            if (!getMax && qAlpha(image.pixel(x, image.height() - y - 1)) > 20) {
                leftBottom.setX(x );
                leftBottom.setY(image.height() - y - 1);
                getMax = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {
            break;
        }
    }
    getMax = false;
    getMin = false;
    for (int x = image.width() - 1; x > 0; --x) {
        for (int y = 0; y < image.height(); ++y) {
            if (!getMin && qAlpha(image.pixel(x, y)) > 20) {
                rightTop.setX(x);
                rightTop.setY(y);
                getMin = true;
            }
            if (!getMax && qAlpha(image.pixel(x, image.height() - y - 1)) > 20) {
                rightBottom.setX(x);
                rightBottom.setY(image.height() - y - 1);
                getMax = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {
            break;
        }
    }

    //如果这四个点组成的4条线不平行或不相等则认为无底
    if (topLeft.y() != topRight.y() || leftTop.x() != leftBottom.x()
        || bottomLeft.y() != bottomRight.y() || rightTop.x() != rightBottom.x()) {
        return true;
    }
    auto threshold = image.width() >= 32? 1 : 0;
    if (qAbs((topRight.x() - topLeft.x()) - (bottomRight.x() - bottomLeft.x())) > threshold || qAbs((leftBottom.y() - leftTop.y()) - (rightBottom.y() - rightTop.y())) > threshold) {
        return true;
    }

    int topOpaquePointCount = 0;
    int bottomOpaquePointCount = 0;
    int leftOpaquePointCount = 0;
    int rightOpaquePointCount = 0;
    for (int y = leftTop.y(); y <= leftBottom.y(); ++y) {
        if (qAlpha(image.pixel(leftTop.x(), y)) > 25) {
            ++leftOpaquePointCount;
        }
    }

    for (int x = topLeft.x(); x <= topRight.x(); ++x) {
        if (qAlpha(image.pixel(x, topLeft.y())) > 25) {
            ++topOpaquePointCount;
        }
    }
    for (int y = rightTop.y(); y <= rightBottom.y(); ++y) {
        if (qAlpha(image.pixel(rightTop.x(), y)) > 25) {
            ++rightOpaquePointCount;
        }
    }
    for (int x = bottomLeft.x(); x <= bottomRight.x(); ++x) {
        if (qAlpha(image.pixel(x, bottomLeft.y())) > 25) {
            ++bottomOpaquePointCount;
        }
    }
    //如果这四条线上的不透明点小于58%则认为无底 (58%来自一个典型的圆形图标 某歌浏览器)
    if (topOpaquePointCount < image.width() * 0.58 ||
        bottomOpaquePointCount < image.width() * 0.58 ||
        leftOpaquePointCount < image.height() * 0.58 ||
        rightOpaquePointCount < image.height() * 0.58) {
        return true;
    }
    return false;
}

bool Icon::isFirstPartyIcon(const QImage &effectArea, int size)
{
    //根据当前主题获取第一方图标的欧氏距离
    QVarLengthArray<qreal, 256> distance;
    QSize itemSize = this->size().toSize();
    QImage image;
    if (d->icon.availableSizes().contains(itemSize) || d->icon.actualSize(itemSize) != itemSize) {
        distance = IconBackgroundUtils::instance()->outLineDistance(size);
        image = effectArea.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    } else {
        distance = IconBackgroundUtils::instance()->outLineDistance(512);
        image = getEffectiveArea(d->icon.pixmap(512).toImage()).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    int contradictoryCount = 0;
    int transparencyAlpha = size >= 64 ? 0 : 3;
    //找到图片的最外层不透明边界，计算欧氏距离并和第一方图标模板进行比较，总体误差低于百分之10认为是第一方图标
    int centerX = image.width()/2 - 1;
    int centerY = image.height()/2 - 1;

    const uchar *pixels = image.constBits();
    const int bytesPerLine = image.bytesPerLine(); // 每行字节数
    for(int x = 0; x < image.width(); x++) {
        for(int y = 0; y < image.height(); y++) {
            const uchar *line = pixels + y * bytesPerLine;
            if(qAlpha(*reinterpret_cast<const QRgb*>(line + x * 4)) > transparencyAlpha) {
                qreal dTemp = qSqrt(qPow(x - centerX, 2) + qPow(y - centerY, 2));
                if(qAbs(distance[x] - dTemp) > 2) {
                    ++contradictoryCount;
                }
                break;
            }
        }
    }
    for(int x = 0; x < image.width(); ++x) {
        for(int y = image.height() - 1; y >= 0; --y) {
            const uchar *line = pixels + y * bytesPerLine;
            if(qAlpha(*reinterpret_cast<const QRgb*>(line + x * 4)) > transparencyAlpha) {
                qreal dTemp = qSqrt(qPow(x - centerX, 2) + qPow(y - centerY, 2));
                if(qAbs(distance[x + 64] - dTemp) > 2) {
                    ++contradictoryCount;
                }
                break;
            }
        }
    }
    for(int y = 0; y < image.height(); ++y) {
        for(int x = 0; x < image.width(); ++x) {
            const uchar *line = pixels + y * bytesPerLine;
            if(qAlpha(*reinterpret_cast<const QRgb*>(line + x * 4)) > transparencyAlpha) {
                qreal dTemp = qSqrt(qPow(x - centerX, 2) + qPow(y - centerY, 2));
                if(qAbs(distance[y + 128] - dTemp) > 2) {
                    ++contradictoryCount;
                }
                break;
            }
        }
    }
    for(int y = 0; y < image.height(); ++y) {
        for(int x = image.width() - 1; x >= 0; --x) {
            const uchar *line = pixels + y * bytesPerLine;
            if(qAlpha(*reinterpret_cast<const QRgb*>(line + x * 4)) > transparencyAlpha) {
                qreal dTemp = qSqrt(qPow(x - centerX, 2) + qPow(y - centerY, 2));
                if(qAbs(distance[y + 192] - dTemp) > 2) {
                    ++contradictoryCount;
                }
                break;
            }
        }
    }
    return contradictoryCount <= 10;
}

void Icon::getImageType(const QImage &effectArea, const QImage &image, int imageSize, int standardEffectAreaSize)
{
    if(effectArea.isNull()) {
        d->imageType = Icon::Uninitialized;
    }

    if (isFirstPartyIcon(effectArea, imageSize)) {
        if (!IconBackgroundUtils::instance()->containShadow(imageSize)
            && !(effectArea.width() == standardEffectAreaSize && effectArea.height() == effectArea.width())) {
            if(!isTransparencyBackground(image)) {
                d->imageType = RectangleWithBack;
            } else {
                d->imageType = Other;
            }
            return;
        }
        d->imageType = Icon::FirstParty;
        return;
    }

    if(qAbs(effectArea.width() - effectArea.height()) >= 2) {
        if(effectArea.width() > effectArea.height() + 1) {
            d->imageType = Icon::RectangleHorizontal;
        } else if (effectArea.width() + 1 < effectArea.height()) {
            d->imageType = Icon::RectangleVertical;
        }
    } else if(!isTransparencyBackground(image)) {
        d->imageType = Icon::RectangleWithBack;
    } else {
        d->imageType = Icon::Other;
    }
}

QImage Icon::getEffectiveArea(const QImage &image)
{
    //从上到下，从下到上，从左到右，从右到左，找到图片中第一个非透明像素点
    QPoint top(0,0), right(0,0), left(0,0), bottom(0,0);
    bool getMax = false;
    bool getMin = false;

    const uchar *pixels = image.constBits();
    const int bytesPerLine = image.bytesPerLine(); // 每行字节数
    int transparencyAlpha = IconBackgroundUtils::instance()->containShadow(image.width()) ? 2 : 4;
    for (int y = 0; y < image.height(); ++y) {
        const uchar *lineTop = pixels + y * bytesPerLine;
        const uchar *lineBottom = pixels + (image.height() - y - 1) * bytesPerLine;
        for (int x = 0; x < image.width(); ++x) {
            if (!getMax && qAlpha(*reinterpret_cast<const QRgb*>(lineTop + x * 4)) > transparencyAlpha) {
                top.setX(x);
                top.setY(y);
                getMax = true;
            }
            if (!getMin && qAlpha(*reinterpret_cast<const QRgb*>(lineBottom + x * 4)) > transparencyAlpha) {
                bottom.setX(x);
                bottom.setY(image.height() - y - 1);
                getMin = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {

            break;
        }
    }

    getMax = false;
    getMin = false;
    for (int x = 0; x < image.width(); ++x) {
        for (int y = 0; y < image.height(); ++y) {
            const uchar *line = pixels + y * bytesPerLine;
            if (!getMax && qAlpha(*reinterpret_cast<const QRgb*>(line + x * 4)) > transparencyAlpha) {
                left.setX(x);
                left.setY(y);
                getMax = true;
            }
            if (!getMin && qAlpha(*reinterpret_cast<const QRgb*>(line + (image.width() - x - 1) * 4)) > transparencyAlpha) {
                right.setX(image.width() - x - 1);
                right.setY(y);
                getMin = true;
            }
            if(getMax && getMin) {
                break;
            }
        }
        if(getMax && getMin) {
            break;
        }
    }

    //在非透明像素点中找到x和y的最大值和最小值
    auto xMax = std::max({top.x(),bottom.x(),left.x(),right.x()});
    auto xMin = std::min({top.x(),bottom.x(),left.x(),right.x()});
    auto yMax = std::max({top.y(),bottom.y(),left.y(),right.y()});
    auto yMin = std::min({top.y(),bottom.y(),left.y(),right.y()});

    //如果为透明图片，返回原图
    if(xMax == 0 || yMax == 0) {
        return image;
    }
    //根据计算出来的非透明点找到有效区域并截取出来
    return image.copy(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
}

bool Icon::isImagePureColor(QImage &image)
{
    if(image.format() != QImage::Format_ARGB32) {
        image = image.convertToFormat(QImage::Format_ARGB32);
    }
    const uchar *pixels = image.constBits();
    const int bytesPerLine = image.bytesPerLine(); // 每行字节数
    bool isPureColor = true;
    QVector<QRgb> vector;
    int total_red = 0;
    int total_green = 0;
    int total_blue = 0;
    int symbolicRed = d->symbolicColor.red();
    int symbolicGreen = d->symbolicColor.green();
    int symbolicBlue = d->symbolicColor.blue();
    for(int y = 0; y < image.height(); y++) {
        const uchar *line = pixels + y * bytesPerLine;
        for(int x = 0; x < image.width(); x++) {
            const QRgb* color = reinterpret_cast<const QRgb*>(line + x * 4);
            if(qAlpha(*color) > 0.3 * 256) {
                int red = qRed(*color);
                int green = qGreen(*color);
                int blue = qBlue(*color);
                vector.append(*color);
                total_red += red;
                total_green += green;
                total_blue += blue;
                if(!isPureColor) {
                    continue;
                }
                if(qAbs(symbolicRed - red) > COLOR_DIFFERENCE || qAbs(symbolicGreen - green) > COLOR_DIFFERENCE
                        || qAbs(symbolicBlue - blue) > COLOR_DIFFERENCE) {
                    isPureColor = false;
                }
            }

        }
    }
    if(isPureColor || vector.count() == 0) {
        return true;
    }
    qreal squareRoot_red = 0;
    qreal squareRoot_green = 0;
    qreal squareRoot_blue = 0;
    qreal average_red = total_red / vector.count();
    qreal average_green = total_green / vector.count();
    qreal average_blue = total_blue / vector.count();
    for (QRgb rgb : vector) {
        squareRoot_red += qPow(qRed(rgb) - average_red, 2);
        squareRoot_green += qPow(qGreen(rgb) - average_green, 2);
        squareRoot_blue += qPow(qBlue(rgb) - average_blue, 2);
    }

    qreal arithmeticSquareRoot_red = qSqrt(squareRoot_red / vector.count());
    qreal arithmeticSquareRoot_green = qSqrt(squareRoot_green / vector.count());
    qreal arithmeticSquareRoot_blue = qSqrt(squareRoot_blue / vector.count());

    return arithmeticSquareRoot_red < 2.0 && arithmeticSquareRoot_green < 2.0 && arithmeticSquareRoot_blue < 2.0;
}

QHash<QPair<int, int>, int> Icon::getTransparentPoint(const QImage &image)
{
    QHash<QPair<int, int>, int> imageAlphaList;
    const uchar *pixels = image.constBits();
    int bytesPerLine = image.bytesPerLine();
    for (int y = 0; y < image.height(); y++) {
        const QRgb* line = reinterpret_cast<const QRgb*>(pixels + y * bytesPerLine);
        for (int x = 0; x < image.width(); x++) {
            const QRgb &color = line[x];
            if (qAlpha(color) != 255) {
                imageAlphaList.insert(QPair(x, y),qAlpha(color));
            }
        }
    }
    return imageAlphaList;

}
} // UkuiQuick
