previewimageprovider.cpp 4.03 KB
Newer Older
1
/*
2
    SPDX-FileCopyrightText: 2018 Julian Wolff <wolff@julianwolff.de>
3

4
    SPDX-License-Identifier: LGPL-2.0-or-later
5
6
*/

7
8
#include <cmath>

9
10
11
12
13
14
15
16
17
18
#include <QApplication>
#include <QPainter>
#include <QPalette>

#include <KWindowSystem>

#include "kxftconfig.h"
#include "previewimageprovider.h"
#include "previewrenderengine.h"

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * @brief Combines a list of images vertically into one image
 *
 * Combines a list of images vertically with the given spacing
 * between adjacent rows of images.
 * The width of the combined image is the width of the longest
 * image in the list, and the height is the sum of the heights
 * of all images in the list.
 * The device pixel ratio of the combined image is the same
 * as that of the first image in the list.
 *
 * @param images the list of images to be combined
 * @param bgnd the background color of the combined image
 * @param _spacing the spacing between adjacent rows of images
 * @return the combined image
 */
QImage combineImages(const QList<QImage> &images, const QColor &bgnd, int _spacing = 0)
36
{
37
38
39
40
    if (images.empty()) {
        return QImage();
    }

41
42
    int width = 0;
    int height = 0;
43
44
    const double devicePixelRatio = images.at(0).devicePixelRatio();
    const int spacing = std::lround(_spacing * devicePixelRatio);
Alexander Lohnau's avatar
Alexander Lohnau committed
45
46
    for (const auto &image : images) {
        if (width < image.width()) {
47
48
            width = image.width();
        }
49
        height += image.height();
50
    }
51
    height += spacing * images.count();
Alexander Lohnau's avatar
Alexander Lohnau committed
52
53

    // To correctly align the image pixels on a high dpi display,
54
    // the image dimensions need to be a multiple of devicePixelRatio
55
    QImage combinedImage(width * devicePixelRatio, height * devicePixelRatio, images.at(0).format());
56
57
    combinedImage.setDevicePixelRatio(devicePixelRatio);
    combinedImage.fill(bgnd);
Alexander Lohnau's avatar
Alexander Lohnau committed
58

59
    int offset = spacing; // Top margin
60
    QPainter p(&combinedImage);
Alexander Lohnau's avatar
Alexander Lohnau committed
61
    for (const auto &image : images) {
62
        p.drawImage(0, offset, image);
63
        offset += image.height() + spacing;
64
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
65

66
67
68
    return combinedImage;
}

Alexander Lohnau's avatar
Alexander Lohnau committed
69
PreviewImageProvider::PreviewImageProvider(const QFont &font)
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    : QQuickImageProvider(QQuickImageProvider::Image)
    , m_font(font)
{
}

QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
    Q_UNUSED(requestedSize)
    if (!KWindowSystem::isPlatformX11()) {
        return QImage();
    }

    int subPixelIndex = 0;
    int hintingIndex = 0;
Alexander Lohnau's avatar
Alexander Lohnau committed
84

85
    const auto idpart = QStringView(id).split(QLatin1Char('.'))[0];
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    const auto sections = idpart.split(QLatin1Char('_'));

    if (sections.size() >= 2) {
        subPixelIndex = sections[0].toInt() + KXftConfig::SubPixel::None;
        hintingIndex = sections[1].toInt() + KXftConfig::Hint::None;
    } else {
        return QImage();
    }

    KXftConfig xft;

    KXftConfig::AntiAliasing::State oldAntialiasing = xft.getAntiAliasing();
    double oldStart = 0;
    double oldEnd = 0;
    xft.getExcludeRange(oldStart, oldEnd);
    KXftConfig::SubPixel::Type oldSubPixelType = KXftConfig::SubPixel::NotSet;
    xft.getSubPixelType(oldSubPixelType);
    KXftConfig::Hint::Style oldHintStyle = KXftConfig::Hint::NotSet;
    xft.getHintStyle(oldHintStyle);
Alexander Lohnau's avatar
Alexander Lohnau committed
105

106
107
    xft.setAntiAliasing(KXftConfig::AntiAliasing::Enabled);
    xft.setExcludeRange(0, 0);
Alexander Lohnau's avatar
Alexander Lohnau committed
108

109
110
    KXftConfig::SubPixel::Type subPixelType = (KXftConfig::SubPixel::Type)subPixelIndex;
    xft.setSubPixelType(subPixelType);
Alexander Lohnau's avatar
Alexander Lohnau committed
111

112
113
    KXftConfig::Hint::Style hintStyle = (KXftConfig::Hint::Style)hintingIndex;
    xft.setHintStyle(hintStyle);
Alexander Lohnau's avatar
Alexander Lohnau committed
114

115
    xft.apply();
Alexander Lohnau's avatar
Alexander Lohnau committed
116

117
118
    QColor text(QApplication::palette().color(QPalette::Text));
    QColor bgnd(QApplication::palette().color(QPalette::Window));
Alexander Lohnau's avatar
Alexander Lohnau committed
119

120
121
    PreviewRenderEngine eng(true);
    QList<QImage> lines;
Alexander Lohnau's avatar
Alexander Lohnau committed
122

123
    lines << eng.drawAutoSize(m_font, text, bgnd, eng.getDefaultPreviewString());
Alexander Lohnau's avatar
Alexander Lohnau committed
124
125
126

    QImage img = combineImages(lines, bgnd, lines[0].height() * .25);

127
128
129
130
    xft.setAntiAliasing(oldAntialiasing);
    xft.setExcludeRange(oldStart, oldEnd);
    xft.setSubPixelType(oldSubPixelType);
    xft.setHintStyle(oldHintStyle);
Alexander Lohnau's avatar
Alexander Lohnau committed
131

132
    xft.apply();
Alexander Lohnau's avatar
Alexander Lohnau committed
133

134
    *size = img.size();
Alexander Lohnau's avatar
Alexander Lohnau committed
135

136
137
    return img;
}