File indexing completed on 2024-04-28 04:58:03
0001 /* This file is part of the KDE libraries 0002 SPDX-FileCopyrightText: 2000 Carsten Pfeiffer <pfeiffer@kde.org> 0003 SPDX-FileCopyrightText: 2000 Malte Starostik <malte@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "imagecreator.h" 0009 0010 #include <QImageReader> 0011 0012 #include <KMemoryInfo> 0013 #include <KPluginFactory> 0014 0015 K_PLUGIN_CLASS_WITH_JSON(ImageCreator, "imagethumbnail.json") 0016 0017 ImageCreator::ImageCreator(QObject *parent, const QVariantList &args) 0018 : KIO::ThumbnailCreator(parent, args) 0019 { 0020 } 0021 0022 #define MiB(bytes) ((bytes)*1024ll * 1024ll) 0023 #define GiB(bytes) (MiB(bytes) * 1024ll) 0024 0025 // When the ram check is disabled or not available, this is the expected default value of free RAM 0026 #define DEFAULT_FREE_RAM GiB(2) 0027 0028 // The maximum usable RAM is the free RAM is divided by this number: 0029 // if the calculated image size is greater than this value, the preview is skipped. 0030 #define RAM_DIVISOR 3 0031 0032 // An image smaller than 64 MiB will be loaded even if the usable RAM check fails. 0033 #define MINIMUM_GUARANTEED_SIZE MiB(64) 0034 0035 /** 0036 * @brief maximumThumbnailRam 0037 * Calculates the maximum RAM that can be used to generate the thumbnail. 0038 * 0039 * The value returned is a third of the available free RAM. 0040 */ 0041 qint64 maximumThumbnailRam() 0042 { 0043 // read available RAM (physical free ram only) 0044 auto freeRam = DEFAULT_FREE_RAM; 0045 0046 KMemoryInfo m; 0047 if (!m.isNull()) { 0048 freeRam = qint64(m.availablePhysical()); 0049 } 0050 0051 /* 0052 * NOTE 1: a minimal 64MiB image is always guaranteed (this small size should never cause OS thrashing). 0053 * NOTE 2: the freeRam is divided by 3 for the following reasons: 0054 * - the image could be converted (e.g. when depth() != 32) 0055 * - we don't want to use all free ram for a thumbnail :) 0056 */ 0057 return std::max(MINIMUM_GUARANTEED_SIZE, freeRam / RAM_DIVISOR); 0058 } 0059 0060 KIO::ThumbnailResult ImageCreator::create(const KIO::ThumbnailRequest &request) 0061 { 0062 // create image preview 0063 QImageReader ir(request.url().toLocalFile()); 0064 0065 /* The idea is to read the free ram and try to avoid OS trashing when the 0066 * image is too big: 0067 * - Qt 6: we can simply limit the maximum size that image reader can handle. 0068 * - Qt 5: the image plugin that allows big images should help us by implementing 0069 * the QImageIOHandler::Size option (TIFF, PSB and XCF already have). 0070 */ 0071 auto ram = maximumThumbnailRam(); 0072 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0073 if (ir.supportsOption(QImageIOHandler::Size)) { 0074 auto size = ir.size(); 0075 // euristic way: we always calculate the size supposing a 16-bits RGBA image 0076 if (size == QSize() || (8ll * size.width() * size.height() > ram)) { 0077 return KIO::ThumbnailResult::fail(); 0078 } 0079 } 0080 #else 0081 QImageReader::setAllocationLimit(ram / 1024 / 1024); 0082 #endif 0083 0084 ir.setAutoTransform(true); 0085 ir.setDecideFormatFromContent(true); 0086 if (ir.format() == QByteArray("raw")) { 0087 // make preview generation of raw files ~3 times faster (requires setDecideFormatFromContent(true)) 0088 ir.setQuality(1); 0089 } 0090 0091 QImage img; 0092 ir.read(&img); 0093 0094 if (!img.isNull()) { 0095 return KIO::ThumbnailResult::pass(img); 0096 } 0097 0098 return KIO::ThumbnailResult::fail(); 0099 } 0100 0101 #include "imagecreator.moc" 0102 #include "moc_imagecreator.cpp"