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 }