mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
581 lines
14 KiB
C++
581 lines
14 KiB
C++
/** ===========================================================
|
|
* @file
|
|
*
|
|
* This file is a part of digiKam project
|
|
* <a href="http://www.digikam.org">http://www.digikam.org</a>
|
|
*
|
|
* @date 2006-12-09
|
|
* @brief a tread-safe libraw C++ program interface
|
|
*
|
|
* @author Copyright (C) 2006-2013 by Gilles Caulier
|
|
* <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a>
|
|
* @author Copyright (C) 2006-2013 by Marcel Wiesweg
|
|
* <a href="mailto:marcel dot wiesweg at gmx dot de">marcel dot wiesweg at gmx dot de</a>
|
|
* @author Copyright (C) 2007-2008 by Guillaume Castagnino
|
|
* <a href="mailto:casta at xwing dot info">casta at xwing dot info</a>
|
|
*
|
|
* This program is free software; you can redistribute it
|
|
* and/or modify it under the terms of the GNU General
|
|
* Public License as published by the Free Software Foundation;
|
|
* either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* ============================================================ */
|
|
|
|
#include "moc_kdcraw.cpp"
|
|
#include "kdcraw_p.h"
|
|
|
|
// Qt includes
|
|
|
|
#include <QFile>
|
|
#include <QFileInfo>
|
|
#include <QStringList>
|
|
|
|
// KDE includes
|
|
#include <kglobal.h>
|
|
|
|
// LibRaw includes
|
|
|
|
#include <libraw_version.h>
|
|
|
|
#ifdef LIBRAW_HAS_CONFIG
|
|
#include <libraw_config.h>
|
|
#endif
|
|
|
|
// Local includes
|
|
|
|
#include "version.h"
|
|
#include "rawfiles.h"
|
|
|
|
static const KCatalogLoader loader("libkdcraw");
|
|
|
|
namespace KDcrawIface
|
|
{
|
|
|
|
KDcraw::KDcraw()
|
|
: d(new Private(this))
|
|
{
|
|
m_cancel = false;
|
|
}
|
|
|
|
KDcraw::~KDcraw()
|
|
{
|
|
cancel();
|
|
delete d;
|
|
}
|
|
|
|
QString KDcraw::version()
|
|
{
|
|
return QString(kdcraw_version);
|
|
}
|
|
|
|
void KDcraw::cancel()
|
|
{
|
|
m_cancel = true;
|
|
}
|
|
|
|
bool KDcraw::loadRawPreview(QImage& image, const QString& path)
|
|
{
|
|
// In first, try to extract the embedded JPEG preview. Very fast.
|
|
bool ret = loadEmbeddedPreview(image, path);
|
|
|
|
if (ret)
|
|
return true;
|
|
|
|
// In second, decode and half size of RAW picture. More slow.
|
|
return (loadHalfPreview(image, path));
|
|
}
|
|
|
|
bool KDcraw::loadEmbeddedPreview(QImage& image, const QString& path)
|
|
{
|
|
QByteArray imgData;
|
|
|
|
if ( loadEmbeddedPreview(imgData, path) )
|
|
{
|
|
kDebug() << "Preview data size:" << imgData.size();
|
|
|
|
if (image.loadFromData( imgData ))
|
|
{
|
|
kDebug() << "Using embedded RAW preview extraction";
|
|
return true;
|
|
}
|
|
}
|
|
|
|
kDebug() << "Failed to load embedded RAW preview";
|
|
return false;
|
|
}
|
|
|
|
bool KDcraw::loadEmbeddedPreview(QByteArray& imgData, const QString& path)
|
|
{
|
|
QFileInfo fileInfo(path);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
LibRaw raw;
|
|
|
|
int ret = raw.open_file(QFile::encodeName(path));
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
return (Private::loadEmbeddedPreview(imgData, raw));
|
|
}
|
|
|
|
bool KDcraw::loadEmbeddedPreview(QByteArray& imgData, const QBuffer& buffer)
|
|
{
|
|
QString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
|
|
LibRaw raw;
|
|
|
|
QByteArray inData = buffer.data();
|
|
int ret = raw.open_buffer((void*) inData.data(), (size_t) inData.size());
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run open_buffer: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
return (Private::loadEmbeddedPreview(imgData, raw));
|
|
}
|
|
|
|
bool KDcraw::loadHalfPreview(QImage& image, const QString& path)
|
|
{
|
|
QFileInfo fileInfo(path);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
kDebug() << "Try to use reduced RAW picture extraction";
|
|
|
|
LibRaw raw;
|
|
raw.imgdata.params.use_auto_wb = 1; // Use automatic white balance.
|
|
raw.imgdata.params.use_camera_wb = 1; // Use camera white balance, if possible.
|
|
raw.imgdata.params.half_size = 1; // Half-size color image (3x faster than -q).
|
|
|
|
int ret = raw.open_file(QFile::encodeName(path));
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
|
|
if(!Private::loadHalfPreview(image, raw))
|
|
{
|
|
kDebug() << "Failed to get half preview from LibRaw!";
|
|
return false;
|
|
}
|
|
|
|
kDebug() << "Using reduced RAW picture extraction";
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KDcraw::loadHalfPreview(QByteArray& imgData, const QString& path)
|
|
{
|
|
QFileInfo fileInfo(path);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
kDebug() << "Try to use reduced RAW picture extraction";
|
|
|
|
LibRaw raw;
|
|
int ret = raw.open_file(QFile::encodeName(path));
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
QImage image;
|
|
|
|
if (!Private::loadHalfPreview(image, raw))
|
|
{
|
|
kDebug() << "KDcraw: failed to get half preview: " << libraw_strerror(ret);
|
|
return false;
|
|
}
|
|
|
|
QBuffer buffer(&imgData);
|
|
buffer.open(QIODevice::WriteOnly);
|
|
image.save(&buffer, "JPEG");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KDcraw::loadHalfPreview(QByteArray& imgData, const QBuffer& inBuffer)
|
|
{
|
|
QString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
|
|
LibRaw raw;
|
|
|
|
QByteArray inData = inBuffer.data();
|
|
int ret = raw.open_buffer((void*) inData.data(), (size_t) inData.size());
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
QImage image;
|
|
|
|
if (!Private::loadHalfPreview(image, raw))
|
|
{
|
|
kDebug() << "KDcraw: failed to get half preview: " << libraw_strerror(ret);
|
|
return false;
|
|
}
|
|
|
|
QBuffer buffer(&imgData);
|
|
buffer.open(QIODevice::WriteOnly);
|
|
image.save(&buffer, "JPG");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KDcraw::loadFullImage(QImage& image, const QString& path, const RawDecodingSettings& settings)
|
|
{
|
|
QFileInfo fileInfo(path);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
kDebug() << "Try to load full RAW picture...";
|
|
|
|
RawDecodingSettings prm = settings;
|
|
prm.sixteenBitsImage = false;
|
|
QByteArray imgData;
|
|
int width, height, rgbmax;
|
|
|
|
KDcraw decoder;
|
|
bool ret = decoder.decodeRAWImage(path, prm, imgData, width, height, rgbmax);
|
|
|
|
if (!ret)
|
|
{
|
|
kDebug() << "Failled to load full RAW picture";
|
|
return false;
|
|
}
|
|
|
|
uchar* sptr = (uchar*)imgData.data();
|
|
uchar tmp8[2];
|
|
|
|
// Set RGB color components.
|
|
for (int i = 0 ; i < width * height ; ++i)
|
|
{
|
|
// Swap Red and Blue
|
|
tmp8[0] = sptr[2];
|
|
tmp8[1] = sptr[0];
|
|
sptr[0] = tmp8[0];
|
|
sptr[2] = tmp8[1];
|
|
|
|
sptr += 3;
|
|
}
|
|
|
|
image = QImage(width, height, QImage::Format_ARGB32);
|
|
uint* dptr = reinterpret_cast<uint*>(image.bits());
|
|
sptr = (uchar*)imgData.data();
|
|
|
|
for (int i = 0 ; i < width * height ; ++i)
|
|
{
|
|
*dptr++ = qRgba(sptr[2], sptr[1], sptr[0], 0xFF);
|
|
sptr += 3;
|
|
}
|
|
|
|
kDebug() << "Load full RAW picture done";
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KDcraw::rawFileIdentify(DcrawInfoContainer& identify, const QString& path)
|
|
{
|
|
QFileInfo fileInfo(path);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
identify.isDecodable = false;
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
LibRaw raw;
|
|
|
|
int ret = raw.open_file(QFile::encodeName(path));
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
ret = raw.adjust_sizes_info_only();
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run adjust_sizes_info_only: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
Private::fillIndentifyInfo(&raw, identify);
|
|
raw.recycle();
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------
|
|
|
|
bool KDcraw::extractRAWData(const QString& filePath, QByteArray& rawData, DcrawInfoContainer& identify, unsigned int shotSelect)
|
|
{
|
|
QFileInfo fileInfo(filePath);
|
|
QString rawFilesExt(rawFiles());
|
|
QString ext = fileInfo.suffix().toUpper();
|
|
identify.isDecodable = false;
|
|
|
|
if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
|
|
return false;
|
|
|
|
if (m_cancel)
|
|
return false;
|
|
|
|
d->setProgress(0.1);
|
|
|
|
LibRaw raw;
|
|
// Set progress call back function.
|
|
raw.set_progress_handler(callbackForLibRaw, d);
|
|
|
|
int ret = raw.open_file(QFile::encodeName(filePath));
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
if (m_cancel)
|
|
{
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
d->setProgress(0.3);
|
|
|
|
raw.imgdata.params.output_bps = 16;
|
|
raw.imgdata.params.shot_select = shotSelect;
|
|
ret = raw.unpack();
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
if (m_cancel)
|
|
{
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
d->setProgress(0.4);
|
|
|
|
ret = raw.raw2image();
|
|
|
|
if (ret != LIBRAW_SUCCESS)
|
|
{
|
|
kDebug() << "LibRaw: failed to run raw2image: " << libraw_strerror(ret);
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
if (m_cancel)
|
|
{
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
d->setProgress(0.6);
|
|
|
|
Private::fillIndentifyInfo(&raw, identify);
|
|
|
|
if (m_cancel)
|
|
{
|
|
raw.recycle();
|
|
return false;
|
|
}
|
|
|
|
d->setProgress(0.8);
|
|
|
|
rawData = QByteArray();
|
|
|
|
if (raw.imgdata.idata.filters == 0)
|
|
{
|
|
rawData.resize((int)(raw.imgdata.sizes.iwidth * raw.imgdata.sizes.iheight * raw.imgdata.idata.colors * sizeof(unsigned short)));
|
|
|
|
unsigned short* output = reinterpret_cast<unsigned short*>(rawData.data());
|
|
|
|
for (unsigned int row = 0; row < raw.imgdata.sizes.iheight; row++)
|
|
{
|
|
for (unsigned int col = 0; col < raw.imgdata.sizes.iwidth; col++)
|
|
{
|
|
for (int color = 0; color < raw.imgdata.idata.colors; color++)
|
|
{
|
|
*output = raw.imgdata.image[raw.imgdata.sizes.iwidth*row + col][color];
|
|
output++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rawData.resize((int)(raw.imgdata.sizes.iwidth * raw.imgdata.sizes.iheight * sizeof(unsigned short)));
|
|
|
|
unsigned short* output = reinterpret_cast<unsigned short*>(rawData.data());
|
|
|
|
for (uint row = 0; row < raw.imgdata.sizes.iheight; row++)
|
|
{
|
|
for (uint col = 0; col < raw.imgdata.sizes.iwidth; col++)
|
|
{
|
|
*output = raw.imgdata.image[raw.imgdata.sizes.iwidth*row + col][raw.COLOR(row, col)];
|
|
output++;
|
|
}
|
|
}
|
|
}
|
|
|
|
raw.recycle();
|
|
d->setProgress(1.0);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KDcraw::decodeHalfRAWImage(const QString& filePath, const RawDecodingSettings& rawDecodingSettings,
|
|
QByteArray& imageData, int& width, int& height, int& rgbmax)
|
|
{
|
|
m_rawDecodingSettings = rawDecodingSettings;
|
|
m_rawDecodingSettings.halfSizeColorImage = true;
|
|
return (d->loadFromLibraw(filePath, imageData, width, height, rgbmax));
|
|
}
|
|
|
|
bool KDcraw::decodeRAWImage(const QString& filePath, const RawDecodingSettings& rawDecodingSettings,
|
|
QByteArray& imageData, int& width, int& height, int& rgbmax)
|
|
{
|
|
m_rawDecodingSettings = rawDecodingSettings;
|
|
return (d->loadFromLibraw(filePath, imageData, width, height, rgbmax));
|
|
}
|
|
|
|
bool KDcraw::checkToCancelWaitingData()
|
|
{
|
|
return m_cancel;
|
|
}
|
|
|
|
void KDcraw::setWaitingDataProgress(double)
|
|
{
|
|
}
|
|
|
|
const char* KDcraw::rawFiles()
|
|
{
|
|
return raw_file_extentions;
|
|
}
|
|
|
|
QStringList KDcraw::rawFilesList()
|
|
{
|
|
QString string = QString::fromLatin1(rawFiles());
|
|
return string.remove("*.").split(' ');
|
|
}
|
|
|
|
int KDcraw::rawFilesVersion()
|
|
{
|
|
return raw_file_extensions_version;
|
|
}
|
|
|
|
QStringList KDcraw::supportedCamera()
|
|
{
|
|
QStringList camera;
|
|
const char** const list = LibRaw::cameraList();
|
|
|
|
for (int i = 0; i < LibRaw::cameraCount(); i++)
|
|
camera.append(list[i]);
|
|
|
|
return camera;
|
|
}
|
|
|
|
QString KDcraw::librawVersion()
|
|
{
|
|
return QString(LIBRAW_VERSION_STR).remove("-Release");
|
|
}
|
|
|
|
int KDcraw::librawUseGomp()
|
|
{
|
|
#ifdef LIBRAW_HAS_CONFIG
|
|
# ifdef LIBRAW_USE_OPENMP
|
|
return true;
|
|
# else
|
|
return false;
|
|
# endif
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int KDcraw::librawUseRawSpeed()
|
|
{
|
|
#ifdef LIBRAW_HAS_CONFIG
|
|
# ifdef LIBRAW_USE_RAWSPEED
|
|
return true;
|
|
# else
|
|
return false;
|
|
# endif
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int KDcraw::librawUseGPL2DemosaicPack()
|
|
{
|
|
#ifdef LIBRAW_HAS_CONFIG
|
|
# ifdef LIBRAW_USE_DEMOSAIC_PACK_GPL2
|
|
return true;
|
|
# else
|
|
return false;
|
|
# endif
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int KDcraw::librawUseGPL3DemosaicPack()
|
|
{
|
|
#ifdef LIBRAW_HAS_CONFIG
|
|
# ifdef LIBRAW_USE_DEMOSAIC_PACK_GPL3
|
|
return true;
|
|
# else
|
|
return false;
|
|
# endif
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
} // namespace KDcrawIface
|