File indexing completed on 2024-05-05 04:22:00

0001 /* SPDX-FileCopyrightText: 2003-2020 The KPhotoAlbum Development Team
0002 
0003    SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "ImageLoaderThread.h"
0007 
0008 #include "AsyncLoader.h"
0009 #include "ImageDecoder.h"
0010 #include "ImageEvent.h"
0011 #include "RawImageDecoder.h"
0012 
0013 #include <Utilities/FastJpeg.h>
0014 #include <Utilities/ImageUtil.h>
0015 #include <kpabase/Logging.h>
0016 #include <kpathumbnails/ThumbnailCache.h>
0017 
0018 #include <QApplication>
0019 #include <QFileInfo>
0020 #include <QLoggingCategory>
0021 
0022 #include <qmatrix.h>
0023 
0024 namespace ImageManager
0025 {
0026 // Create a global instance. Its constructor will itself register it.
0027 RAWImageDecoder rawdecoder;
0028 }
0029 
0030 ImageManager::ImageLoaderThread::ImageLoaderThread(size_t bufsize)
0031     : m_imageLoadBuffer(new char[bufsize])
0032     , m_bufSize(bufsize)
0033 {
0034 }
0035 
0036 ImageManager::ImageLoaderThread::~ImageLoaderThread()
0037 {
0038     delete[] m_imageLoadBuffer;
0039 }
0040 
0041 void ImageManager::ImageLoaderThread::run()
0042 {
0043     while (true) {
0044         ImageRequest *request = AsyncLoader::instance()->next();
0045         Q_ASSERT(request);
0046         if (request->isExitRequest()) {
0047             return;
0048         }
0049         bool ok;
0050 
0051         QImage img = loadImage(request, ok);
0052 
0053         if (ok) {
0054             img = scaleAndRotate(request, img);
0055         }
0056 
0057         request->setLoadedOK(ok);
0058         ImageEvent *iew = new ImageEvent(request, img);
0059         QApplication::postEvent(AsyncLoader::instance(), iew);
0060     }
0061 }
0062 
0063 QImage ImageManager::ImageLoaderThread::loadImage(ImageRequest *request, bool &ok)
0064 {
0065     int dim = calcLoadSize(request);
0066     QSize fullSize;
0067 
0068     ok = false;
0069     if (!request->fileSystemFileName().exists())
0070         return QImage();
0071 
0072     QImage img;
0073     if (Utilities::isJPEG(request->fileSystemFileName())) {
0074         ok = Utilities::loadJPEG(&img, request->fileSystemFileName(), &fullSize, dim,
0075                                  m_imageLoadBuffer, m_bufSize);
0076         if (ok == true)
0077             request->setFullSize(fullSize);
0078     }
0079 
0080     else {
0081         // At first, we have to give our RAW decoders a try. If we allowed
0082         // QImage's load() method, it'd for example load a tiny thumbnail from
0083         // NEF files, which is not what we want.
0084         ok = ImageDecoder::decode(&img, request, &fullSize, dim);
0085         if (ok)
0086             request->setFullSize(img.size());
0087     }
0088 
0089     if (!ok) {
0090         // Now we can try QImage's stuff as a fallback...
0091         ok = img.load(request->fileSystemFileName().absolute());
0092         if (ok)
0093             request->setFullSize(img.size());
0094     }
0095 
0096     return img;
0097 }
0098 
0099 int ImageManager::ImageLoaderThread::calcLoadSize(ImageRequest *request)
0100 {
0101     return qMax(request->width(), request->height());
0102 }
0103 
0104 QImage ImageManager::ImageLoaderThread::scaleAndRotate(ImageRequest *request, QImage img)
0105 {
0106     if (request->angle() != 0 && !request->imageIsPreRotated()) {
0107         QTransform matrix;
0108         matrix.rotate(request->angle());
0109         img = img.transformed(matrix);
0110         int angle = (request->angle() + 360) % 360;
0111         Q_ASSERT(angle >= 0 && angle <= 360);
0112         qCDebug(ImageManagerLog) << "Rotating image to" << angle << "degrees:" << request->fileSystemFileName().relative();
0113         if (angle == 90 || angle == 270)
0114             request->setFullSize(QSize(request->fullSize().height(), request->fullSize().width()));
0115     }
0116 
0117     // If we are looking for a scaled version, then scale
0118     if (shouldImageBeScale(img, request))
0119         img = Utilities::scaleImage(img, request->size(), Qt::KeepAspectRatio);
0120 
0121     return img;
0122 }
0123 
0124 bool ImageManager::ImageLoaderThread::shouldImageBeScale(const QImage &img, ImageRequest *request)
0125 {
0126     // No size specified, meaning we want it full size.
0127     if (request->width() == -1)
0128         return false;
0129 
0130     if (img.width() < request->width() && img.height() < request->height()) {
0131         // The image is smaller than the requets.
0132         return request->doUpScale();
0133     }
0134 
0135     return true;
0136 }
0137 // vi:expandtab:tabstop=4 shiftwidth=4: