Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_raw_import.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "kis_raw_import.h"
8
9#include <cmath>
10#include <cstddef>
11#include <exiv2/exiv2.hpp>
12#include <utility>
13#include <kpluginfactory.h>
14#include <libkdcraw_version.h>
15
16#include <kdcraw.h>
17
19#include <KisDocument.h>
20#include <KisExiv2IODevice.h>
22#include <KoColorSpace.h>
24#include <KoColorSpaceTraits.h>
25#include <KoDialog.h>
26#include <KoUpdater.h>
27#include <kis_debug.h>
28#include <kis_group_layer.h>
29#include <kis_image.h>
32#include <kis_meta_data_tags.h>
33#include <kis_paint_device.h>
34#include <kis_paint_layer.h>
36#include <kis_transaction.h>
37
38using namespace KDcrawIface;
39
40class Q_DECL_HIDDEN MyKDcraw : public KDcraw
41{
42public:
44 : updater(std::move(updater))
45 {
46 }
47
48 void setWaitingDataProgress(double value) override
49 {
50 if (updater)
51 updater->setProgress(static_cast<int>(value * 100.0));
52 }
53
54private:
56};
57
58K_PLUGIN_FACTORY_WITH_JSON(KisRawImportFactory, "krita_raw_import.json", registerPlugin<KisRawImport>();)
59
60KisRawImport::KisRawImport(QObject *parent, const QVariantList &)
61 : KisImportExportFilter(parent)
62 , m_dialog(new KoDialog())
63 , m_rawWidget(new WdgRawImport())
64{
65 m_dialog->setButtons(KoDialog::Ok | KoDialog::Cancel | KoDialog::Apply);
66 m_dialog->setDefaultButton(KoDialog::Ok);
67
68 m_dialog->setMainWidget(m_rawWidget);
71 connect(m_rawWidget->rawSettings, &DcrawSettingsWidget::signalSettingsChanged, [&]() {
72 m_dialog->enableButtonApply(true);
73 });
74}
75
80
81inline quint16 correctIndian(quint16 v)
82{
83#if KDCRAW_VERSION < 0x000400
84 return ((v & 0x00FF) << 8) | ((v & 0xFF00 >> 8));
85#else
86 return v;
87#endif
88}
89
91KisRawImport::convert(KisDocument *document, QIODevice * /*io*/, KisPropertiesConfigurationSP /*configuration*/)
92{
93#if KDCRAW_VERSION < 0x010200
94 m_rawWidget->rawSettings->setDefaultSettings();
95#else
96 m_rawWidget->rawSettings->resetToDefault();
97#endif
98
99 int r = QDialog::Accepted;
100 if (!batchMode()) {
101 r = m_dialog->exec();
102 }
103
104 if (r == QDialog::Accepted) {
105 KisCursorOverrideLock cursorLock(Qt::WaitCursor);
106
107 // Do the decoding
108 QByteArray imageData;
109 RawDecodingSettings settings = rawDecodingSettings();
110 settings.sixteenBitsImage = true;
111 int width = 0;
112 int height = 0;
113 int rgbmax = 0;
114 MyKDcraw dcraw(updater());
115 if (!dcraw.decodeRAWImage(filename(), settings, imageData, width, height, rgbmax))
117
118 const KoColorProfile *profile = nullptr;
119
120 switch (settings.outputColorSpace) {
121 case RawDecodingSettings::RAWCOLOR:
122 case RawDecodingSettings::SRGB:
124 break;
125 case RawDecodingSettings::ADOBERGB:
126 profile = KoColorSpaceRegistry::instance()->profileByName("ClayRGB-elle-V2-g22.icc");
127 break;
128 case RawDecodingSettings::WIDEGAMMUT:
129 profile = KoColorSpaceRegistry::instance()->profileByName("WideRGB-elle-V2-g22.icc");
130 break;
131 case RawDecodingSettings::PROPHOTO:
132 profile = KoColorSpaceRegistry::instance()->profileByName("LargeRGB-elle-V2-g22.icc");
133 break;
134 case RawDecodingSettings::CUSTOMOUTPUTCS:
135 QFileInfo info(settings.outputProfile);
136
137 if (!info.exists()) {
138 qWarning() << "WARNING: couldn't find custom profile" << settings.outputProfile;
140 } else {
141 QFile profileFile(settings.outputProfile);
142
143 if (profileFile.open(QFile::ReadOnly)) {
146 profileFile.readAll());
147 } else {
148 qWarning() << "WARNING: couldn't open custom profile file" << settings.outputProfile;
149 }
150 }
151
152 if (!profile) {
153 qWarning() << "WARNING: reset profile to sRGB";
155 }
156
157 break;
158 }
159
160 // Init the image
161 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb16(profile);
162 KisImageSP image = new KisImage(document->createUndoStore(), width, height, cs, filename());
164
165 KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), quint8_MAX);
166
167 image->addNode(layer, image->rootLayer());
169
170 KisPaintDeviceSP device = layer->paintDevice();
172
173 const auto readLayer = [](KisLayerSP layer,
174 const QByteArray &imageData,
175 int width,
176 int height,
177 const QPointer<KoUpdater> &updater) -> void {
178 const float original = static_cast<float>(updater->progress());
179 // Leave 10% for the metadata
180 const float step = (static_cast<float>(updater->maximum() * 0.9) - original) / (float)height;
181 // Copy the data
183
184 for (int y = 0; y < height;) {
185 const int numContiguousRows = qMin(it->numContiguousRows(y), height - y);
186 for (int x = 0; x < width;) {
187 const int numContiguousColumns = qMin(it->numContiguousColumns(x), width - x);
188
189 it->moveTo(x, y);
190
191 const int rowStride = it->rowStride(x, y);
192
193 quint8 *d = it->rawData();
194
195 for (int i = 0; i < numContiguousRows; i++) {
196 const auto *ptr =
197 reinterpret_cast<const typename KoBgrU16Traits::channels_type *>(imageData.data())
198 + static_cast<ptrdiff_t>(((y + i) * width + x) * 3);
199
200 for (int j = 0; j < numContiguousColumns; j++) {
201 auto *pixel = reinterpret_cast<typename KoBgrU16Traits::Pixel *>(d) + j;
202#if KDCRAW_VERSION < 0x000400
203 pixel->red = correctIndian(ptr[2]);
204 pixel->green = correctIndian(ptr[1]);
205 pixel->blue = correctIndian(ptr[0]);
206 pixel->alpha = 0xFFFF;
207#else
208 *pixel = {correctIndian(ptr[2]), correctIndian(ptr[1]), correctIndian(ptr[0]), 0xFFFF};
209#endif
210 ptr += 3;
211 }
212
213 d += rowStride;
214 }
215
216 x += numContiguousColumns;
217 }
218
219 y += numContiguousRows;
220 updater->setProgress(static_cast<int>(original + step * float(y)));
221 }
222 };
223
224 readLayer(layer, imageData, width, height, updater());
225
226 {
227 // HACK!! Externally parse the Exif metadata
228 // libtiff has no way to access the fields wholesale
229 try {
231
232#if EXIV2_TEST_VERSION(0,28,0)
233 const std::unique_ptr<Exiv2::Image> readImg = Exiv2::ImageFactory::open(std::move(basicIoDevice));
234#else
235 const std::unique_ptr<Exiv2::Image> readImg(Exiv2::ImageFactory::open(basicIoDevice).release());
236#endif
237
238 readImg->readMetadata();
239
241
242 // All IFDs are paint layer children of root
243 KisNodeSP node = image->rootLayer()->firstChild();
244
245 QBuffer ioDevice;
246
247 {
248 // Synthesize the Exif blob
249 Exiv2::ExifData tempData;
250 Exiv2::Blob tempBlob;
251
252 // NOTE: do not use std::copy_if, auto_ptrs beware
253 for (const Exiv2::Exifdatum &i : readImg->exifData()) {
254 const uint16_t tag = i.tag();
255
266 dbgMetaData << "Ignoring TIFF-specific" << i.key().c_str();
267 continue;
268 }
269
270 tempData.add(i);
271 }
272
273 // Encode into temporary blob
274 Exiv2::ExifParser::encode(tempBlob, Exiv2::littleEndian, tempData);
275
276 // Reencode into Qt land
277 ioDevice.setData(reinterpret_cast<char *>(tempBlob.data()), static_cast<int>(tempBlob.size()));
278 }
279
280 // Get layer
281 KisLayer *layer = qobject_cast<KisLayer *>(node.data());
282 KIS_ASSERT_RECOVER(layer)
283 {
284 errFile << "Attempted to import metadata on an empty document";
286 }
287
288 // Inject the data as any other IOBackend
289 io->loadFrom(layer->metaData(), &ioDevice);
290#if EXIV2_TEST_VERSION(0,28,0)
291 } catch (Exiv2::Error &e) {
292 errFile << "Failed injecting TIFF metadata:" << Exiv2::Error(e.code()).what();
293#else
294 } catch (Exiv2::AnyError &e) {
295 errFile << "Failed metadata import:" << e.code() << e.what();
296#endif
297 }
298 }
299
300 document->setCurrentImage(image);
301 updater()->setProgress(updater()->maximum());
303 }
304
306}
307
309{
310 QByteArray imageData;
311 RawDecodingSettings settings = rawDecodingSettings();
312 settings.sixteenBitsImage = false;
313 int width = 0;
314 int height = 0;
315 int rgbmax = 0;
316 KDcraw dcraw;
317 if (dcraw.decodeHalfRAWImage(filename(), settings, imageData, width, height, rgbmax)) {
318 QImage image(width, height, QImage::Format_RGB32);
319 quint8 *ptr = reinterpret_cast<quint8 *>(imageData.data());
320 for (int y = 0; y < height; ++y) {
321 QRgb *pixel = reinterpret_cast<QRgb *>(image.scanLine(y));
322 for (int x = 0; x < width; ++x) {
323 pixel[x] = qRgb(ptr[0], ptr[1], ptr[2]);
324 ptr += 3;
325 }
326 }
327 const QSize previewSize = m_rawWidget->preview->size() * m_rawWidget->preview->devicePixelRatioF();
328 QPixmap img = QPixmap::fromImage(image).scaled(previewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
329 img.setDevicePixelRatio(m_rawWidget->preview->devicePixelRatioF());
330 m_rawWidget->preview->setPixmap(img);
331 }
332
334}
335
337{
338#if KDCRAW_VERSION < 0x010200
339 RawDecodingSettings settings;
340 settings.sixteenBitsImage = true;
341 settings.brightness = m_rawWidget->rawSettings->brightness();
342 settings.RAWQuality = m_rawWidget->rawSettings->quality();
343 settings.outputColorSpace = m_rawWidget->rawSettings->outputColorSpace();
344 settings.RGBInterpolate4Colors = m_rawWidget->rawSettings->useFourColor();
345 settings.DontStretchPixels = m_rawWidget->rawSettings->useDontStretchPixels();
346 settings.unclipColors = m_rawWidget->rawSettings->unclipColor();
347 settings.whiteBalance = m_rawWidget->rawSettings->whiteBalance();
348 settings.customWhiteBalance = m_rawWidget->rawSettings->customWhiteBalance();
349 settings.customWhiteBalanceGreen = m_rawWidget->rawSettings->customWhiteBalanceGreen();
350
351 settings.enableBlackPoint = m_rawWidget->rawSettings->useBlackPoint();
352 settings.blackPoint = m_rawWidget->rawSettings->blackPoint();
353
354 settings.enableNoiseReduction = m_rawWidget->rawSettings->useNoiseReduction();
355 settings.NRThreshold = m_rawWidget->rawSettings->NRThreshold();
356
357 settings.enableCACorrection = m_rawWidget->rawSettings->useCACorrection();
358 settings.caMultiplier[0] = m_rawWidget->rawSettings->caRedMultiplier();
359 settings.caMultiplier[1] = m_rawWidget->rawSettings->caBlueMultiplier();
360
361 return settings;
362#else
363 return m_rawWidget->rawSettings->settings();
364#endif
365}
366
367#include "kis_raw_import.moc"
float value(const T *src, size_t ch)
qreal v
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
virtual quint8 * rawData()=0
Exiv2::BasicIo::AutoPtr ptr_type
KisGroupLayerSP rootLayer() const
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
The base class for import and export filters.
QPointer< KoUpdater > updater
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
static KisMetadataBackendRegistry * instance()
KisRandomAccessorSP createRandomAccessorNG()
virtual qint32 rowStride(qint32 x, qint32 y) const =0
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
virtual qint32 numContiguousColumns(qint32 x) const =0
~KisRawImport() override
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=0) override
KDcrawIface::RawDecodingSettings rawDecodingSettings()
KoDialog * m_dialog
KisRawImport(QObject *parent, const QVariantList &)
WdgRawImport * m_rawWidget
bool isNull() const
A dialog base class with standard buttons and predefined layouts.
Definition KoDialog.h:116
void applyClicked()
void enableButtonApply(bool state)
Definition KoDialog.cpp:620
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition KoDialog.h:127
@ Apply
Show Apply button.
Definition KoDialog.h:128
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition KoDialog.h:130
const T value(const QString &id) const
QString id() const
Definition KoID.cpp:63
QPointer< KoUpdater > updater
MyKDcraw(QPointer< KoUpdater > updater)
void setWaitingDataProgress(double value) override
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
unsigned int QRgb
#define errFile
Definition kis_debug.h:115
#define dbgMetaData
Definition kis_debug.h:61
const quint8 quint8_MAX
Definition kis_global.h:24
quint16 correctIndian(quint16 v)
const uint16_t ImageLength
const uint16_t PrimaryChromaticities
const uint16_t ReferenceBlackWhite
const uint16_t ImageWidth
const uint16_t PlanarConfiguration
const uint16_t YResolution
const uint16_t XResolution
const uint16_t TransferFunction
const uint16_t Orientation
const uint16_t ResolutionUnit
const uint16_t YCbCrSubSampling
const uint16_t SamplesPerPixel
const uint16_t BitsPerSample
const uint16_t Compression
const uint16_t InterColorProfile
const uint16_t YCbCrCoefficients
const uint16_t YCbCrPositioning
const uint16_t WhitePoint
const uint16_t PhotometricInterpretation
KisMetaData::Store * metaData()
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
KisNodeSP firstChild() const
Definition kis_node.cpp:361
KisPaintDeviceSP paintDevice
const KoColorProfile * profileByName(const QString &name) const
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorSpace * rgb16(const QString &profileName=QString())
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
_channels_type_ channels_type
the type of the value of the channels of this color space