Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/kio-extras/thumbnail/icoutils.cpp
Line
Count
Source
1
/*
2
    icoutils.cpp - Extract Microsoft Window icons and images
3
4
    SPDX-FileCopyrightText: 2009-2010 Pali Rohár <pali.rohar@gmail.com>
5
6
    SPDX-License-Identifier: GPL-2.0-or-later
7
*/
8
9
#include "icoutils.h"
10
#include "exeutils.h"
11
12
#include <QBuffer>
13
#include <QImage>
14
#include <QImageReader>
15
#include <QList>
16
#include <QString>
17
#include <QTemporaryFile>
18
19
#include <algorithm>
20
21
namespace
22
{
23
24
qreal distance(int width, int height, int desiredWidth, int desiredHeight, int depth)
25
70.6M
{
26
    // We want as high of a depth as possible (32-bit)
27
70.6M
    auto targetSamples = desiredWidth * desiredHeight * 32;
28
70.6M
    auto xscale = (1.0 * desiredWidth) / width;
29
70.6M
    auto yscale = (1.0 * desiredHeight) / height;
30
31
    // clamp to the lower of the two scales
32
    // also clamp to one, as scaling up adds no effective
33
    // samples, only interpolated samples
34
70.6M
    auto sampleScale = std::min(1.0, std::min(xscale, yscale));
35
36
    // number of effective source samples in the target
37
70.6M
    auto effectiveSamples = width * height * sampleScale * sampleScale * depth;
38
    // scale down another time, to account for loss of fidelity when
39
    // using a downscaled image, biases towards smaller downscaling ratios
40
70.6M
    effectiveSamples *= sampleScale;
41
42
70.6M
    return targetSamples - effectiveSamples;
43
70.6M
}
44
45
}
46
47
bool IcoUtils::loadIcoImageFromExe(QIODevice *inputDevice, QImage &image, int needWidth, int needHeight)
48
3.69k
{
49
3.69k
    QBuffer iconData;
50
3.69k
    if (!iconData.open(QIODevice::ReadWrite)) {
51
0
        return false;
52
0
    }
53
54
3.69k
    if (!ExeUtils::loadIcoDataFromExe(inputDevice, &iconData))
55
2.35k
        return false;
56
57
1.34k
    if (!iconData.seek(0)) {
58
0
        return false;
59
0
    }
60
61
1.34k
    return IcoUtils::loadIcoImage(&iconData, image, needWidth, needHeight);
62
1.34k
}
63
64
bool IcoUtils::loadIcoImageFromExe(const QString &inputFileName, QImage &image, int needWidth, int needHeight)
65
3.69k
{
66
3.69k
    QFile inputFile{inputFileName};
67
68
3.69k
    if (!inputFile.open(QIODevice::ReadOnly)) {
69
0
        return false;
70
0
    }
71
72
3.69k
    return IcoUtils::loadIcoImageFromExe(&inputFile, image, needWidth, needHeight);
73
3.69k
}
74
75
bool IcoUtils::loadIcoImage(QImageReader &reader, QImage &image, int needWidth, int needHeight)
76
4.75k
{
77
    // QTBUG-70812: for files with incorrect bits per pixel, QImageReader::canRead() returns
78
    // false but it can still correctly determine the imageCount() and read the icon just fine.
79
4.75k
    if (reader.imageCount() == 0) {
80
451
        return false;
81
451
    }
82
83
4.30k
    QList<QImage> icons;
84
4.30k
    do
85
70.6M
        icons << reader.read();
86
70.6M
    while (reader.jumpToNextImage());
87
88
4.30k
    if (icons.empty())
89
0
        return false;
90
91
4.30k
    int index = icons.size() - 1;
92
4.30k
    qreal best = std::numeric_limits<qreal>::max();
93
94
70.6M
    for (int i = 0; i < icons.size(); ++i) {
95
70.6M
        const QImage &icon = icons.at(i);
96
97
        // QtIcoHandler converts all images to 32-bit depth,
98
        // but it stores the actual depth of the icon extracted in custom text:
99
        // qtbase/src/plugins/imageformats/ico/qicohandler.cpp:455
100
70.6M
        int depth = icon.text(QStringLiteral("_q_icoOrigDepth")).toInt();
101
70.6M
        if (depth == 0 || depth > 32) {
102
70.5M
            depth = icon.depth();
103
70.5M
        }
104
105
70.6M
        const qreal dist = distance(icon.width(), icon.height(), needWidth, needHeight, depth);
106
107
70.6M
        if (dist < best) {
108
7.31k
            index = i;
109
7.31k
            best = dist;
110
7.31k
        }
111
70.6M
    }
112
113
4.30k
    image = icons.at(index);
114
4.30k
    return true;
115
4.30k
}
116
117
bool IcoUtils::loadIcoImage(QIODevice *inputDevice, QImage &image, int needWidth, int needHeight)
118
1.34k
{
119
1.34k
    QImageReader reader(inputDevice, "ico");
120
1.34k
    return IcoUtils::loadIcoImage(reader, image, needWidth, needHeight);
121
1.34k
}
122
123
bool IcoUtils::loadIcoImage(const QString &inputFileName, QImage &image, int needWidth, int needHeight)
124
3.40k
{
125
3.40k
    QImageReader reader(inputFileName, "ico");
126
3.40k
    return IcoUtils::loadIcoImage(reader, image, needWidth, needHeight);
127
3.40k
}