File indexing completed on 2024-05-19 04:29:13
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Eugene Ingerman geneing at gmail dot com 0003 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "KisImageThumbnailStrokeStrategy.h" 0009 0010 #include <kis_paint_device.h> 0011 #include <kis_painter.h> 0012 #include "krita_utils.h" 0013 #include "kis_transform_worker.h" 0014 #include "kis_filter_strategy.h" 0015 #include <KoColorSpaceRegistry.h> 0016 #include <KoUpdater.h> 0017 #include "KisRunnableStrokeJobUtils.h" 0018 #include "KisRunnableStrokeJobsInterface.h" 0019 0020 const qreal oversample = 2.; 0021 const int thumbnailTileDim = 128; 0022 0023 0024 KisImageThumbnailStrokeStrategyBase:: 0025 KisImageThumbnailStrokeStrategyBase(KisPaintDeviceSP device, 0026 const QRect& rect, 0027 const QSize& thumbnailSize, 0028 bool isPixelArt, 0029 const KoColorProfile *profile, 0030 KoColorConversionTransformation::Intent renderingIntent, 0031 KoColorConversionTransformation::ConversionFlags conversionFlags) 0032 : KisIdleTaskStrokeStrategy(QLatin1String("OverviewThumbnail"), kundo2_i18n("Update overview thumbnail")), 0033 m_device(device), 0034 m_rect(rect), 0035 m_thumbnailSize(thumbnailSize), 0036 m_isPixelArt(isPixelArt), 0037 m_profile(profile), 0038 m_renderingIntent(renderingIntent), 0039 m_conversionFlags(conversionFlags) 0040 { 0041 } 0042 0043 KisImageThumbnailStrokeStrategyBase::~KisImageThumbnailStrokeStrategyBase() 0044 { 0045 } 0046 0047 void KisImageThumbnailStrokeStrategyBase::initStrokeCallback() 0048 { 0049 using KritaUtils::addJobConcurrent; 0050 using KritaUtils::addJobSequential; 0051 KisIdleTaskStrokeStrategy::initStrokeCallback(); 0052 0053 const QRect imageRect = m_device->defaultBounds()->bounds(); 0054 0055 m_thumbnailOversampledSize = oversample * m_thumbnailSize; 0056 0057 if ((m_thumbnailOversampledSize.width() > imageRect.width()) || (m_thumbnailOversampledSize.height() > imageRect.height())) { 0058 m_thumbnailOversampledSize.scale(imageRect.size(), Qt::KeepAspectRatio); 0059 } 0060 0061 m_thumbnailDevice = new KisPaintDevice(m_device->colorSpace()); 0062 0063 QVector<KisRunnableStrokeJobData*> jobs; 0064 0065 QVector<QRect> tileRects = KritaUtils::splitRectIntoPatches(QRect(QPoint(0, 0), m_thumbnailOversampledSize), QSize(thumbnailTileDim, thumbnailTileDim)); 0066 Q_FOREACH (const QRect &rc, tileRects) { 0067 addJobConcurrent(jobs, [this, tileRect = rc] () { 0068 //we aren't going to use oversample capability of createThumbnailDevice because it recomputes exact bounds for each small patch, which is 0069 //slow. We'll handle scaling separately. 0070 KisPaintDeviceSP thumbnailTile = m_device->createThumbnailDeviceOversampled(m_thumbnailOversampledSize.width(), m_thumbnailOversampledSize.height(), 1, m_device->defaultBounds()->bounds(), tileRect); 0071 KisPainter::copyAreaOptimized(tileRect.topLeft(), thumbnailTile, m_thumbnailDevice, tileRect); 0072 }); 0073 } 0074 0075 addJobSequential(jobs, [this] () { 0076 KoDummyUpdaterHolder updaterHolder; 0077 qreal xscale = m_thumbnailSize.width() / (qreal)m_thumbnailOversampledSize.width(); 0078 qreal yscale = m_thumbnailSize.height() / (qreal)m_thumbnailOversampledSize.height(); 0079 QString algorithm = m_isPixelArt ? "Box" : "Bilinear"; 0080 KisTransformWorker worker(m_thumbnailDevice, xscale, yscale, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0081 updaterHolder.updater(), KisFilterStrategyRegistry::instance()->value(algorithm)); 0082 worker.run(); 0083 0084 reportThumbnailGenerationCompleted(m_thumbnailDevice, QRect(QPoint(0,0), m_thumbnailSize)); 0085 }); 0086 0087 runnableJobsInterface()->addRunnableJobs(jobs); 0088 } 0089 0090 void KisImageThumbnailStrokeStrategy::reportThumbnailGenerationCompleted(KisPaintDeviceSP device, const QRect &rect) 0091 { 0092 QImage overviewImage; 0093 overviewImage = device->convertToQImage(m_profile, 0094 rect, 0095 m_renderingIntent, 0096 m_conversionFlags); 0097 emit thumbnailUpdated(overviewImage); 0098 }