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