RAW: Allow preview loading

This patch addresses reports of performance issues on large raw collections. Programs that generate previews must use the plugin correctly.

**Setting quality to 0 may return a different image than in the past** (Nothing changes for all other quality values): the plugin loads the embedded thumbnail and, in case of error, decodes the image with quality 1. When compiled with libRAW 0.21+, the plugin automatically select the largest preview from the ones in the file.
This commit is contained in:
Mirco Miranda 2025-01-08 07:01:57 +00:00
parent c97ee00f5e
commit 1982557a55
2 changed files with 80 additions and 4 deletions

View File

@ -581,6 +581,66 @@ void setParams(QImageIOHandler *handler, LibRaw *rawProcessor)
params.use_fuji_rotate = T_SR(quality) ? 0 : 1;
}
bool LoadTHUMB(QImageIOHandler *handler, QImage &img)
{
std::unique_ptr<LibRaw> rawProcessor(new LibRaw);
// *** Open the stream
auto device = handler->device();
#ifndef EXCLUDE_LibRaw_QIODevice
LibRaw_QIODevice stream(device);
if (rawProcessor->open_datastream(&stream) != LIBRAW_SUCCESS) {
return false;
}
#else
auto ba = device->readAll();
if (rawProcessor->open_buffer(ba.data(), ba.size()) != LIBRAW_SUCCESS) {
return false;
}
#endif
#if (LIBRAW_VERSION < LIBRAW_MAKE_VERSION(0, 21, 0))
// *** Unpacking selected thumbnail
if (rawProcessor->unpack_thumb() != LIBRAW_SUCCESS) {
return false;
}
#else
// *** Search for the bigger thumbnail
auto &&tlist = rawProcessor->imgdata.thumbs_list;
auto idx = 0;
for (auto n = 1; n < std::min(tlist.thumbcount, LIBRAW_THUMBNAIL_MAXCOUNT); ++n) {
if (tlist.thumblist[n].twidth > tlist.thumblist[idx].twidth)
idx = n;
}
// *** Unpacking selected thumbnail
if (rawProcessor->unpack_thumb_ex(idx) != LIBRAW_SUCCESS) {
return false;
}
#endif
// *** Convert to QImage
pi_unique_ptr processedImage(rawProcessor->dcraw_make_mem_thumb(), LibRaw::dcraw_clear_mem);
if (processedImage == nullptr) {
return false;
}
auto ba = QByteArray(reinterpret_cast<const char *>(processedImage->data), qsizetype(processedImage->data_size));
if (ba.isEmpty()) {
return false;
}
if (processedImage->type == LIBRAW_IMAGE_BITMAP) {
// clang-format off
auto header = QString::fromUtf8("P%1\n%2 %3\n%4\n") // taken from KDcraw
.arg(processedImage->colors == 3 ? QLatin1String("6") : QLatin1String("5"))
.arg(processedImage->width)
.arg(processedImage->height)
.arg((1 << processedImage->bits)-1);
// clang-format on
ba.prepend(header.toLatin1());
}
return img.loadFromData(ba);
}
bool LoadRAW(QImageIOHandler *handler, QImage &img)
{
std::unique_ptr<LibRaw> rawProcessor(new LibRaw);
@ -679,6 +739,11 @@ bool LoadRAW(QImageIOHandler *handler, QImage &img)
if (params.output_color == 7) {
img.setColorSpace(QColorSpace(QColorSpace::DisplayP3));
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
if (params.output_color == 8) {
img.setColorSpace(QColorSpace(QColorSpace::Bt2020));
}
#endif
}
// *** Set the metadata
@ -756,7 +821,16 @@ bool RAWHandler::read(QImage *image)
}
QImage img;
if (!LoadRAW(this, img)) {
auto ok = false;
if (m_quality == 0) {
ok = LoadTHUMB(this, img);
if (!ok && !dev->isSequential())
dev->seek(m_startPos);
}
if (!ok) {
ok = LoadRAW(this, img);
}
if (!ok) {
return false;
}

View File

@ -60,7 +60,8 @@ private:
* @note It is safe to set both W and A: W is used if camera white balance is found, otherwise A is used.
*
* When quality is a positive value, a value between 0 and 100 is expected. The values are interpreted as follows:
* - 00-09: I = 0, C = 1, B = 0, W = 1, A = 1, H = 1 (Linear, sRGB, 8-bits, Camera White, Auto White, Half-size)
* - 00 : Embedded preview, if fails same as Half-Size (01-09)
* - 01-09: I = 0, C = 1, B = 0, W = 1, A = 1, H = 1 (Linear, sRGB, 8-bits, Camera White, Auto White, Half-size)
* - 10-19: I = 0, C = 1, B = 0, W = 1, A = 1, H = 0 (Linear, sRGB, 8-bits, Camera White, Auto White)
* - 20-29: I = 3, C = 1, B = 0, W = 1, A = 1, H = 0 (AHD, sRGB, 8-bits, Camera White, Auto White)
* - 30-39: I = 3, C = 1, B = 1, W = 1, A = 1, H = 0 (AHD, sRGB, 16-bits, Camera White, Auto White) [Default]
@ -72,11 +73,12 @@ private:
* - >= 90: I = 11, C = 4, B = 1, W = 1, A = 1, H = 0 (DHT, ProPhoto, 16-bits, Camera White, Auto White)
*
* When the quality is -1, default quality is used.
* @sa m_subType
*/
qint32 m_quality;
/*!
* \brief m_startPos
/**
* @brief m_startPos
* The initial device position to allow multi image load (cache value).
*/
qint64 m_startPos;