Commit 3f861f63 authored by Mirco Miranda's avatar Mirco Miranda Committed by Méven Car
Browse files

Thumbnailer: limit the maximum image size

Try to limit the maximum RAM usable by the thumnailer.
- Should mitigate the CCBUG: 234030
- Patch required by  [Merge request 68 of kimageformats](frameworks/kimageformats!68)
- Tested on Debian Unstable only using the trick suggested by @meven and a lot of QDebug 😄
parent 0ce6ea52
Pipeline #192489 passed with stage
in 3 minutes and 6 seconds
......@@ -86,6 +86,7 @@ add_library(imagethumbnail MODULE imagecreator.cpp)
kcoreaddons_desktop_to_json(imagethumbnail imagethumbnail.desktop)
target_link_libraries(imagethumbnail
KF5::CoreAddons
KF5::KIOWidgets
)
......
......@@ -6,25 +6,87 @@
*/
#include "imagecreator.h"
#include "macros.h"
#include <QImageReader>
#include <kcoreaddons_version.h>
#if KCOREADDONS_VERSION >= QT_VERSION_CHECK(5,95,0)
#include <kmemoryinfo.h>
#endif
EXPORT_THUMBNAILER_WITH_JSON(ImageCreator, "imagethumbnail.json")
#define MiB(bytes) ((bytes) * 1024ll * 1024ll)
#define GiB(bytes) (MiB(bytes) * 1024ll)
// When the ram check is disabled or not available, this is the expected default value of free RAM
#define DEFAULT_FREE_RAM GiB(2)
// The maximum usable RAM is the free RAM is divided by this number:
// if the calculated image size is greater than this value, the preview is skipped.
#define RAM_DIVISOR 3
// An image smaller than 64 MiB will be loaded even if the usable RAM check fails.
#define MINIMUM_GUARANTEED_SIZE MiB(64)
/**
* @brief maximumThumbnailRam
* Calculates the maximum RAM that can be used to generate the thumbnail.
*
* The value returned is a third of the available free RAM.
*/
qint64 maximumThumbnailRam()
{
// read available RAM (physical free ram only)
auto freeRam = DEFAULT_FREE_RAM;
#ifdef KMEMORYINFO_H
KMemoryInfo m;
if (!m.isNull()) {
freeRam = qint64(m.availablePhysical());
}
#endif
/*
* NOTE 1: a minimal 64MiB image is always guaranteed (this small size should never cause OS thrashing).
* NOTE 2: the freeRam is divided by 3 for the following reasons:
* - the image could be converted (e.g. when depth() != 32)
* - we don't want to use all free ram for a thumbnail :)
*/
return std::max(MINIMUM_GUARANTEED_SIZE, freeRam / RAM_DIVISOR);
}
bool ImageCreator::create(const QString &path, int, int, QImage &img)
{
// create image preview
QImageReader ir(path);
/* The idea is to read the free ram and try to avoid OS trashing when the
* image is too big:
* - Qt 6: we can simply limit the maximum size that image reader can handle.
* - Qt 5: the image plugin that allows big images should help us by implementing
* the QImageIOHandler::Size option (TIFF, PSB and XCF already have).
*/
auto ram = maximumThumbnailRam();
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
if (ir.supportsOption(QImageIOHandler::Size)) {
auto size = ir.size();
// euristic way: we always calculate the size supposing a 16-bits RGBA image
if (size == QSize() || (size.width() * size.height() * 8ll > ram)) {
return false;
}
}
#else
QImageReader::setAllocationLimit(ram / 1024);
#endif
ir.setAutoTransform(true);
ir.setDecideFormatFromContent(true);
ir.read(&img);
if (img.isNull())
return false;
if (img.depth() != 32)
if (!img.isNull() && img.depth() != 32) {
img = img.convertToFormat(img.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
return true;
}
return !img.isNull();
}
#include "imagecreator.moc"
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment