00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #ifdef HAVE_SYS_TYPES_H
00022 #include <sys/types.h>
00023 #endif
00024
00025 #include <sys/types.h>
00026 #include <netinet/in.h>
00027
00028 #include <qstring.h>
00029 #include <qfile.h>
00030 #include <qimage.h>
00031 #include <qradiobutton.h>
00032 #include <qgroupbox.h>
00033 #include <qbuttongroup.h>
00034 #include <qpushbutton.h>
00035 #include <qlabel.h>
00036 #include <qcheckbox.h>
00037 #include <qapplication.h>
00038 #include <qcursor.h>
00039 #include <qeventloop.h>
00040 #include <qprogressdialog.h>
00041 #include <qtimer.h>
00042
00043 #include <kglobal.h>
00044 #include <kconfig.h>
00045 #include <knuminput.h>
00046 #include <kgenericfactory.h>
00047 #include <kdialogbase.h>
00048 #include <kdialog.h>
00049 #include <kmessagebox.h>
00050 #include <klocale.h>
00051 #include <kprocess.h>
00052
00053 #include <KoDocument.h>
00054 #include <KoFilterChain.h>
00055
00056 #include "imageviewer.h"
00057 #include "kis_config.h"
00058 #include "kis_cmb_idlist.h"
00059 #include "kis_types.h"
00060 #include "kis_raw_import.h"
00061 #include "kis_doc.h"
00062 #include "kis_image.h"
00063 #include "kis_meta_registry.h"
00064 #include "kis_layer.h"
00065 #include "kis_annotation.h"
00066 #include "kis_profile.h"
00067 #include "kis_colorspace_factory_registry.h"
00068 #include "kis_iterators_pixel.h"
00069 #include "kis_abstract_colorspace.h"
00070 #include "kis_paint_device.h"
00071 #include "kis_paint_layer.h"
00072 #include "wdgrawimport.h"
00073
00074 typedef KGenericFactory<KisRawImport, KoFilter> KisRawImportFactory;
00075 K_EXPORT_COMPONENT_FACTORY(libkrita_raw_import, KisRawImportFactory("kofficefilters"))
00076
00077 KisRawImport::KisRawImport(KoFilter *, const char *, const QStringList&)
00078 : KoFilter()
00079 , m_data(0)
00080 , m_process(0)
00081 , m_progress(0)
00082 {
00083 m_dialog = new KDialogBase();
00084 m_dialog->enableButtonApply(false);
00085 m_page = new WdgRawImport(m_dialog);
00086 m_dialog -> setMainWidget(m_page);
00087
00088 connect(m_page->bnPreview, SIGNAL(clicked()), this, SLOT(slotUpdatePreview()));
00089 connect(m_page->grpColorSpace, SIGNAL(clicked( int )), this, SLOT(slotFillCmbProfiles()));
00090 connect(m_page->grpChannelDepth, SIGNAL(clicked( int )), this, SLOT(slotFillCmbProfiles()));
00091
00092 KisConfig cfg;
00093 QString monitorProfileName = cfg.monitorProfile();
00094 m_monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName);
00095
00096 slotFillCmbProfiles();
00097 }
00098
00099 KisRawImport::~KisRawImport()
00100 {
00101 delete m_dialog;
00102 delete m_process;
00103 }
00104
00105 KoFilter::ConversionStatus KisRawImport::convert(const QCString& from, const QCString& to)
00106 {
00107 if (from != "image/x-raw" || to != "application/x-krita") {
00108 return KoFilter::NotImplemented;
00109 }
00110
00111 kdDebug(41008) << "Krita importing from Raw\n";
00112
00113 KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument());
00114 if (!doc) {
00115 return KoFilter::CreationError;
00116 }
00117
00118 doc -> prepareForImport();
00119
00120 QString filename = m_chain -> inputFile();
00121
00122 if (filename.isEmpty()) {
00123 return KoFilter::FileNotFound;
00124 }
00125
00126 slotUpdatePreview();
00127
00128
00129 m_dialog->setCursor(Qt::ArrowCursor);
00130 QApplication::setOverrideCursor(Qt::ArrowCursor);
00131
00132 KConfig * cfg = KGlobal::config();
00133 cfg->setGroup("rawimport");
00134
00135 m_page->radioGray->setChecked(cfg->readBoolEntry("gray", false));
00136 m_page->radioRGB->setChecked(cfg->readBoolEntry("rgb", true));
00137 m_page->radio8->setChecked(cfg->readBoolEntry("8bit", false));
00138 m_page->radio16->setChecked(cfg->readBoolEntry("16bit", true));
00139 m_page->chkFourColorRGB->setChecked( cfg->readBoolEntry("four_color_rgb", false));
00140 m_page->chkCameraColors->setChecked( cfg->readBoolEntry("camera_colors", false));
00141 m_page->chkBrightness->setChecked( cfg->readBoolEntry("do_brightness", false));
00142 m_page->chkBlackpoint->setChecked( cfg->readBoolEntry("do_blackpoint", false));
00143 m_page->chkRed->setChecked( cfg->readBoolEntry("do_red", false));
00144 m_page->chkBlue->setChecked( cfg->readBoolEntry("do_blue", false));
00145 m_page->radioFixed->setChecked( cfg->readBoolEntry("fixed_wb", true));
00146 m_page->radioAutomatic->setChecked( cfg->readBoolEntry("automatic_wb", false));
00147 m_page->radioCamera->setChecked( cfg->readBoolEntry("camera_wb", false));
00148 m_page->chkClip->setChecked( cfg->readBoolEntry("clip", true));
00149 m_page->chkProfile->setChecked(cfg->readBoolEntry("useprofile", false));
00150 m_page->dblBrightness->setValue(cfg->readDoubleNumEntry("brightness", 1.0));
00151 m_page->dblBlackpoint->setValue(cfg->readDoubleNumEntry("blackpoint", 0));
00152 m_page->dblRed->setValue(cfg->readDoubleNumEntry("red", 1.0));
00153 m_page->dblBlue->setValue(cfg->readDoubleNumEntry("blue", 1.0));
00154
00155 if (m_dialog->exec() == QDialog::Accepted) {
00156
00157 cfg->writeEntry("gray", m_page->radioGray->isChecked());
00158 cfg->writeEntry("rgb", m_page->radioRGB->isChecked());
00159 cfg->writeEntry("8bit", m_page->radio8->isChecked());
00160 cfg->writeEntry("16bit", m_page->radio16->isChecked());
00161 cfg->writeEntry("four_color_rgb", m_page->chkFourColorRGB -> isChecked());
00162 cfg->writeEntry("camera_colors", m_page->chkCameraColors -> isChecked());
00163 cfg->writeEntry("do_brightness", m_page->chkBrightness -> isChecked());
00164 cfg->writeEntry("do_blackpoint", m_page->chkBlackpoint -> isChecked());
00165 cfg->writeEntry("do_red", m_page->chkRed -> isChecked());
00166 cfg->writeEntry("do_blue", m_page->chkBlue -> isChecked());
00167 cfg->writeEntry("fixed_wb", m_page->radioFixed -> isChecked());
00168 cfg->writeEntry("automatic_wb", m_page->radioAutomatic -> isChecked());
00169 cfg->writeEntry("camera_wb", m_page->radioCamera -> isChecked());
00170 cfg->writeEntry("clip", m_page->chkClip->isChecked());
00171 cfg->writeEntry("useprofile", m_page->chkProfile->isChecked());
00172 cfg->writeEntry("brightness", m_page->dblBrightness->value());
00173 cfg->writeEntry("blackpoint", m_page->dblBlackpoint->value());
00174 cfg->writeEntry("red", m_page->dblRed->value());
00175 cfg->writeEntry("blue", m_page->dblBlue->value());
00176
00177 QApplication::setOverrideCursor(Qt::waitCursor);
00178
00179 m_progress = new QProgressDialog();
00180 m_progress -> setTotalSteps(0);
00181 m_progress -> setCancelButton(0);
00182 QTimer timer;
00183 connect(&timer, SIGNAL(timeout()), this, SLOT(incrementProgress()));
00184 timer.start(200);
00185
00186 doc -> undoAdapter() -> setUndo(false);
00187
00188 getImageData(createArgumentList(false));
00189
00190 KisImageSP image = 0;
00191 KisPaintLayerSP layer = 0;
00192 KisPaintDeviceSP device = 0;
00193
00194 QApplication::restoreOverrideCursor();
00195
00196 delete m_progress;
00197 m_progress = 0;
00198
00199 if (m_page->radio8->isChecked()) {
00200
00201
00202 QImage img;
00203 img.loadFromData(*m_data);
00204
00205 KisColorSpace * cs = 0;
00206 if (m_page->radioGray->isChecked()) {
00207 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA"), profile() );
00208 }
00209 else {
00210 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA"), profile() );
00211 }
00212 if (cs == 0) { kdDebug() << "No CS\n"; return KoFilter::InternalError; }
00213
00214 image = new KisImage(doc->undoAdapter(), img.width(), img.height(), cs, filename);
00215 if (image == 0) return KoFilter::CreationError;
00216 image->blockSignals(true);
00217
00218 layer = dynamic_cast<KisPaintLayer*>( image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data() );
00219 if (layer == 0) return KoFilter::CreationError;
00220
00221 device = layer->paintDevice();
00222 if (device == 0) return KoFilter::CreationError;
00223
00224 device->convertFromQImage(img, "");
00225
00226 } else {
00227
00228
00229 Q_UINT32 startOfImagedata = 0;
00230 QSize sz = determineSize(startOfImagedata);
00231
00232 kdDebug(41008) << "Total bytes: " << m_data->size()
00233 << "\n start of image data: " << startOfImagedata
00234 << "\n bytes for pixels left: " << m_data->size() - startOfImagedata
00235 << "\n total pixels: " << sz.width() * sz.height()
00236 << "\n total pixel bytes: " << sz.width() * sz.height() * 6
00237 << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata
00238 << "\n";
00239
00240
00241 char * data = m_data->data() + startOfImagedata;
00242
00243 KisColorSpace * cs = 0;
00244 if (m_page->radioGray->isChecked()) {
00245 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() );
00246 }
00247 else {
00248 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() );
00249 }
00250 if (cs == 0) return KoFilter::InternalError;
00251
00252 image = new KisImage( doc->undoAdapter(), sz.width(), sz.height(), cs, filename);
00253 if (image == 0)return KoFilter::CreationError;
00254
00255 layer = dynamic_cast<KisPaintLayer*> (image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data());
00256 if (layer == 0) return KoFilter::CreationError;
00257
00258 device = layer->paintDevice();
00259 if (device == 0) return KoFilter::CreationError;
00260
00261
00262 int pos = 0;
00263
00264 for (int line = 0; line < sz.height(); ++line) {
00265 KisHLineIterator it = device->createHLineIterator(0, line, sz.width(), true);
00266
00267 while (!it.isDone()) {
00268 if (m_page->radioGray->isChecked()) {
00269 Q_UINT16 d = (Q_INT16)*(data + pos);
00270 d = ntohs(d);
00271 memcpy(it.rawData(), &d, 2);
00272 pos += 2;
00273 }
00274 else {
00275
00276 Q_UINT16 d = (Q_INT16)*(data + pos);
00277 d = ntohs(d);
00278 memcpy(it.rawData() + 4, &d, 2);
00279
00280
00281 pos += 2;
00282 d = (Q_INT16)*(data + pos );
00283 d = ntohs(d);
00284 memcpy(it.rawData() + 2, &d, 2);
00285
00286
00287 pos += 2;
00288 d = (Q_INT16)*(data + pos );
00289 d = ntohs(d);
00290 memcpy(it.rawData(), &d, 2);
00291
00292 pos += 2;
00293 }
00294 cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1);
00295 ++it;
00296 }
00297 }
00298 }
00299 layer->setDirty();
00300 kdDebug() << "going to set image\n";
00301 doc -> setCurrentImage(image);
00302 doc -> undoAdapter() -> setUndo(true);
00303 doc -> setModified(false);
00304 kdDebug() << "everything ok\n";
00305
00306 QApplication::restoreOverrideCursor();
00307 return KoFilter::OK;
00308 }
00309
00310 QApplication::restoreOverrideCursor();
00311 return KoFilter::UserCancelled;
00312 }
00313
00314 void KisRawImport::incrementProgress()
00315 {
00316 m_progress -> setProgress(m_progress -> progress() + 10);
00317 }
00318
00319
00320 void KisRawImport::slotUpdatePreview()
00321 {
00322 QApplication::setOverrideCursor(Qt::waitCursor);
00323 getImageData(createArgumentList(true));
00324
00325 kdDebug(41008) << "Retrieved " << m_data->size() << " bytes of image data\n";
00326
00327 if (m_data->isNull()) return;
00328
00329 QImage img;
00330
00331 if (m_page->radio8->isChecked()) {
00332
00333 img.loadFromData(*m_data);
00334
00335 } else {
00336
00337
00338 Q_UINT32 startOfImagedata = 0;
00339 QSize sz = determineSize(startOfImagedata);
00340
00341 kdDebug(41008) << "Total bytes: " << m_data->size()
00342 << "\n start of image data: " << startOfImagedata
00343 << "\n bytes for pixels left: " << m_data->size() - startOfImagedata
00344 << "\n total pixels: " << sz.width() * sz.height()
00345 << "\n total pixel bytes: " << sz.width() * sz.height() * 6
00346 << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata
00347 << "\n";
00348
00349 char * data = m_data->data() + startOfImagedata;
00350
00351 KisColorSpace * cs = 0;
00352 if (m_page->radioGray->isChecked()) {
00353 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() );
00354 }
00355 else {
00356 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() );
00357 }
00358 KisPaintDevice * dev = new KisPaintDevice(cs, "preview");
00359
00360 int pos = 0;
00361
00362 for (int line = 0; line < sz.height(); ++line) {
00363 KisHLineIterator it = dev->createHLineIterator(0, line, sz.width(), true);
00364
00365 while (!it.isDone()) {
00366 if (m_page->radioGray->isChecked()) {
00367 Q_UINT16 d = (Q_INT16)*(data + pos);
00368 d = ntohs(d);
00369 memcpy(it.rawData(), &d, 2);
00370 pos += 2;
00371 }
00372 else {
00373
00374 Q_UINT16 d = (Q_INT16)*(data + pos);
00375 d = ntohs(d);
00376 memcpy(it.rawData() + 4, &d, 2);
00377
00378
00379 pos += 2;
00380 d = (Q_INT16)*(data + pos );
00381 d = ntohs(d);
00382 memcpy(it.rawData() + 2, &d, 2);
00383
00384
00385 pos += 2;
00386 d = (Q_INT16)*(data + pos );
00387 d = ntohs(d);
00388 memcpy(it.rawData(), &d, 2);
00389
00390 pos += 2;
00391 }
00392 cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1);
00393 ++it;
00394 }
00395 }
00396
00397 img = dev->convertToQImage(m_monitorProfile);
00398 }
00399
00400 m_page->lblPreview->setImage(img);
00401 QApplication::restoreOverrideCursor();
00402 }
00403
00404
00405 void KisRawImport::getImageData( QStringList arguments )
00406 {
00407
00408 delete m_data;
00409
00410 kdDebug(41008) << "getImageData " << arguments.join(" ") << "\n";
00411 KProcess process (this);
00412 m_data = new QByteArray(0);
00413
00414 for (QStringList::iterator it = arguments.begin(); it != arguments.end(); ++it) {
00415 process << *it;
00416 }
00417
00418 process.setUseShell(true);
00419 connect(&process, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(slotReceivedStdout(KProcess *, char *, int)));
00420 connect(&process, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(slotReceivedStderr(KProcess *, char *, int)));
00421 connect(&process, SIGNAL(processExited(KProcess *)), this, SLOT(slotProcessDone()));
00422
00423
00424 kdDebug(41008) << "Starting process\n";
00425
00426 if (!process.start(KProcess::NotifyOnExit, KProcess::AllOutput)) {
00427 KMessageBox::error( 0, i18n("Cannot convert RAW files because the dcraw executable could not be started."));
00428 }
00429 while (process.isRunning()) {
00430
00431 qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
00432
00433 }
00434
00435 if (process.normalExit()) {
00436 kdDebug(41008) << "Return value of process: " << process.exitStatus() << "\n";
00437 }
00438 else {
00439 kdDebug(41008) << "Process did not exit normally. Exit signal: " << process.exitSignal() << "\n";
00440 }
00441
00442 }
00443
00444
00445 void KisRawImport::slotProcessDone()
00446 {
00447 kdDebug(41008) << "process done!\n";
00448 }
00449
00450 void KisRawImport::slotReceivedStdout(KProcess *, char *buffer, int buflen)
00451 {
00452
00453
00454 int oldSize = m_data->size();
00455 m_data->resize(oldSize + buflen, QGArray::SpeedOptim);
00456 memcpy(m_data->data() + oldSize, buffer, buflen);
00457 }
00458
00459 void KisRawImport::slotReceivedStderr(KProcess *, char *buffer, int buflen)
00460 {
00461 QByteArray b(buflen);
00462 memcpy(b.data(), buffer, buflen);
00463 kdDebug(41008) << QString(b) << "\n";
00464
00465 }
00466
00467
00468 QStringList KisRawImport::createArgumentList(bool forPreview)
00469 {
00470 QStringList args;
00471
00472 args.append("dcraw");
00473
00474
00475
00476 args.append("-c");
00477
00478 if (forPreview) {
00479 args.append("-h");
00480 }
00481
00482 if (m_page->radio8->isChecked()) {
00483 args.append("-2");
00484 }
00485 else {
00486 args.append("-4");
00487 }
00488
00489 if (m_page->radioGray->isChecked()) {
00490 args.append("-d");
00491 }
00492
00493 if (m_page->chkCameraColors->isChecked()) {
00494 args.append("-m");
00495 }
00496
00497 if (m_page->radioAutomatic->isChecked()) {
00498 args.append("-a");
00499 }
00500
00501 if (m_page->radioCamera->isChecked()) {
00502 args.append("-w");
00503 }
00504
00505 if (m_page->chkFourColorRGB->isChecked()) {
00506 args.append("-f");
00507 }
00508
00509 if (!m_page->chkClip->isChecked()) {
00510 args.append("-n");
00511 }
00512
00513 if (m_page->chkBrightness->isChecked()) {
00514 args.append("-b " + QString::number(m_page->dblBrightness->value()));
00515 }
00516
00517 if (m_page->chkBlackpoint->isChecked()) {
00518 args.append("-k " + QString::number(m_page->dblBlackpoint->value()));
00519 }
00520
00521 if (m_page->chkRed->isChecked()) {
00522 args.append("-r " + QString::number(m_page->dblRed->value()));
00523 }
00524
00525 if (m_page->chkBlue->isChecked()) {
00526 args.append("-l " + QString::number(m_page->dblBlue->value()));
00527 }
00528
00529
00530 KisProfile * pf = profile();
00531 if (m_page->chkProfile->isChecked()) {
00532 if (!pf->filename().isNull()) {
00533
00534
00535
00536 args.append("-p \"" + pf->filename() + "\"");
00537 }
00538 }
00539
00540
00541 args.append("\"" + m_chain -> inputFile() + "\"");
00542
00543 return args;
00544 }
00545
00546 QSize KisRawImport::determineSize(Q_UINT32& startOfImageData)
00547 {
00548 if (m_data->isNull() || m_data->size() < 2048) {
00549 startOfImageData = 0;
00550 return QSize(0,0);
00551 }
00552
00553 QString magick = QString::fromAscii(m_data->data(), 2);
00554 if (magick != "P6") {
00555 kdDebug(41008) << " Bad magick! " << magick << "\n";
00556 startOfImageData = 0;
00557 return QSize(0,0);
00558 }
00559
00560
00561 Q_UINT32 i = 0;
00562 Q_UINT32 counter = 0;
00563
00564 while (true) {
00565 if (counter == 3) break;
00566 if (m_data->data()[i] == '\n') {
00567 counter++;
00568 }
00569 ++i;
00570 }
00571
00572 QString size = QStringList::split("\n", QString::fromAscii(m_data->data(), i))[1];
00573 kdDebug(41008) << "Header: " << QString::fromAscii(m_data->data(), i) << "\n";
00574 QStringList sizelist = QStringList::split(" ", size);
00575 Q_INT32 w = sizelist[0].toInt();
00576 Q_INT32 h = sizelist[1].toInt();
00577
00578 startOfImageData = i;
00579 return QSize(w, h);
00580
00581 }
00582
00583 KisProfile * KisRawImport::profile()
00584 {
00585 if (m_page->chkProfile->isChecked()) {
00586 return KisMetaRegistry::instance()->csRegistry()->getProfileByName(m_page->cmbProfile->currentText());
00587 }
00588 else
00589 return 0;
00590 }
00591
00592 void KisRawImport::slotFillCmbProfiles()
00593 {
00594 KisID s = getColorSpace();
00595
00596 KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
00597 m_page -> cmbProfile -> clear();
00598 QValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
00599 QValueVector<KisProfile *> ::iterator it;
00600 for ( it = profileList.begin(); it != profileList.end(); ++it ) {
00601 m_page -> cmbProfile -> insertItem((*it) -> productName());
00602 }
00603 }
00604
00605 KisID KisRawImport::getColorSpace()
00606 {
00607 if (m_page->radioRGB->isChecked()) {
00608 if (m_page->radio16->isChecked()) {
00609 return KisID( "RGBA16" );
00610 }
00611 }
00612 else {
00613 if (m_page->radio16->isChecked()) {
00614 return KisID( "GRAYA16" );
00615 }
00616 else {
00617 return KisID( "GRAYA" );
00618 }
00619 }
00620 return KisID("RGBA");
00621 }
00622
00623 #include "kis_raw_import.moc"