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

0001 // SPDX-FileCopyrightText: 2005 Steffen Hansen <hansen@kde.org>
0002 // SPDX-FileCopyrightText: 2005-2012 Jesper K. Pedersen <jesper.pedersen@kdab.com>
0003 // SPDX-FileCopyrightText: 2006-2009 Tuomas Suutari <tuomas@nepnep.net>
0004 // SPDX-FileCopyrightText: 2007 Dirk Mueller <mueller@kde.org>
0005 // SPDX-FileCopyrightText: 2007 Laurent Montel <montel@kde.org>
0006 // SPDX-FileCopyrightText: 2007-2012 Jan Kundrát <jkt@flaska.net>
0007 // SPDX-FileCopyrightText: 2010 Miika Turkia <miika.turkia@gmail.com>
0008 // SPDX-FileCopyrightText: 2012 Rex Dieter <rdieter@math.unl.edu>
0009 // SPDX-FileCopyrightText: 2013-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0010 // SPDX-FileCopyrightText: 2016 Tobias Leupold <tl@stonemx.de>
0011 // SPDX-FileCopyrightText: 2018 Robert Krawitz <rlk@alum.mit.edu>
0012 //
0013 // SPDX-License-Identifier: GPL-2.0-or-later
0014 
0015 #include "RawImageDecoder.h"
0016 
0017 #include "ImageRequest.h"
0018 
0019 #include <Utilities/FastJpeg.h>
0020 #include <kpabase/FileExtensions.h>
0021 #include <kpabase/FileName.h>
0022 #include <kpabase/Logging.h>
0023 #include <kpabase/SettingsData.h>
0024 #include <kpabase/config-kpa-kdcraw.h>
0025 
0026 #include <QFile>
0027 #include <QImage>
0028 #ifdef HAVE_KDCRAW
0029 #include <KDCRAW/KDcraw>
0030 #include <libkdcraw_version.h>
0031 #endif
0032 
0033 namespace ImageManager
0034 {
0035 
0036 bool RAWImageDecoder::_decode(QImage *img, ImageRequest *request, QSize *fullSize, int dim)
0037 {
0038     /* width and height seem to be only hints, ignore */
0039     Q_UNUSED(dim)
0040 
0041 #ifdef HAVE_KDCRAW
0042     QSize size;
0043     QSize *fSize = (fullSize) ? fullSize : &size;
0044     const DB::FileName &imageFile = request->fileSystemFileName();
0045     QByteArray previewData;
0046     if (!KDcrawIface::KDcraw::loadEmbeddedPreview(previewData, imageFile.absolute()))
0047         return false;
0048 
0049     // Faster than allowing loadRawPreview to do the decode itself
0050     if (!Utilities::loadJPEG(img, previewData, fSize, dim))
0051         return false;
0052 
0053     qCDebug(ImageManagerLog) << "Got embedded preview for raw file" << imageFile.relative();
0054     qCDebug(ImageManagerLog) << "  Preview size:" << img->width() << "x" << img->height();
0055     qCDebug(ImageManagerLog) << "  Requested dimension:" << dim;
0056     qCDebug(ImageManagerLog) << "  useRawThumbnail:" << Settings::SettingsData::instance()->useRawThumbnail();
0057     qCDebug(ImageManagerLog) << "  useRawThumbnailSize:" << Settings::SettingsData::instance()->useRawThumbnailSize();
0058 
0059     if (Settings::SettingsData::instance()->useRawThumbnail()
0060         && ((dim > 0 && img->width() >= dim && img->height() >= dim)
0061             || (img->width() >= Settings::SettingsData::instance()->useRawThumbnailSize().width()
0062                 && img->height() >= Settings::SettingsData::instance()->useRawThumbnailSize().height()))) {
0063         qCDebug(ImageManagerLog) << "Preferring embedded raw thumbnail...";
0064         return true;
0065     }
0066 
0067     KDcrawIface::DcrawInfoContainer metadata;
0068     if (!KDcrawIface::KDcraw::rawFileIdentify(metadata, imageFile.absolute()))
0069         return false;
0070     qCDebug(ImageManagerLog) << "  Raw image size:" << metadata.imageSize;
0071     qCDebug(ImageManagerLog) << "  Raw image orientation enum:" << metadata.orientation;
0072     if ((img->width() < metadata.imageSize.width() * 0.8) || (img->height() < metadata.imageSize.height() * 0.8)) {
0073 
0074         qCDebug(ImageManagerLog) << "Decoding the raw image is required...";
0075         // let's try to get a better resolution
0076         KDcrawIface::KDcraw decoder;
0077         KDcrawIface::RawDecodingSettings rawDecodingSettings;
0078 
0079         if (rawDecodingSettings.sixteenBitsImage) {
0080             qCWarning(ImageManagerLog) << "16 bits per color channel is not supported yet";
0081             return false;
0082         } else {
0083             QByteArray imageData; /* 3 bytes for each pixel,  */
0084             int width, height, rgbmax;
0085             if (!decoder.decodeRAWImage(imageFile.absolute(), rawDecodingSettings, imageData, width, height, rgbmax))
0086                 return false;
0087 
0088             // Now the funny part, how to turn this fugly QByteArray into an QImage. Yay!
0089             *img = QImage(width, height, QImage::Format_RGB32);
0090             if (img->isNull())
0091                 return false;
0092 
0093             uchar *data = img->bits();
0094 
0095             for (int i = 0; i < imageData.size(); i += 3, data += 4) {
0096                 data[0] = imageData[i + 2]; // blue
0097                 data[1] = imageData[i + 1]; // green
0098                 data[2] = imageData[i]; // red
0099                 data[3] = 0xff; // alpha
0100             }
0101         }
0102         // The preview data for raw images is always returned in its non-rotated form by libkdcraw,
0103         // but the raw image itself is returned in its rotated form.
0104         // For decoded raw images, we therefore need to tell the ImageLoaderThread not to rotate the image a second time.
0105         request->setImageIsPreRotated(true);
0106 
0107     } else
0108         qCDebug(ImageManagerLog) << "Embedded raw thumbnail is sufficient...";
0109 
0110     *fSize = img->size();
0111 
0112     return true;
0113 #else /* HAVE_KDCRAW */
0114     Q_UNUSED(img)
0115     Q_UNUSED(fullSize)
0116     Q_UNUSED(request)
0117     return false;
0118 #endif /* HAVE_KDCRAW */
0119 }
0120 
0121 bool RAWImageDecoder::_mightDecode(const DB::FileName &imageFile)
0122 {
0123     const auto pref = Settings::SettingsData::instance()->skipRawIfOtherMatches() ? KPABase::FileTypePreference::PreferNonRawFile : KPABase::FileTypePreference::NoPreference;
0124     return KPABase::isUsableRawImage(imageFile, pref);
0125 }
0126 
0127 }
0128 // vi:expandtab:tabstop=4 shiftwidth=4: