14#include <QApplication>
16#include <QPluginLoader>
20#include <QTextBrowser>
25#include <QtConcurrent>
27#include <klocalizedstring.h>
28#include <ksqueezedtextlabel.h>
29#include <kpluginfactory.h>
74 SynchronousUserFeedbackInterface(QWidget *parent,
bool batchMode)
76 , m_batchMode(batchMode)
80 Result askUser(AskCallback callback)
override
82 if (m_batchMode)
return SuppressedByBatchMode;
88 QWidget *m_parent {
nullptr};
89 bool m_batchMode {
false};
148 : m_document(document)
190 QSet<QString> mimeTypes;
197 QJsonObject json = loader.
metaData().value(
"MetaData").toObject();
198 Q_FOREACH(
const QString &mimetype, json.value(
"X-KDE-Import").toString().split(
",", Qt::SkipEmptyParts)) {
201 mimeTypes << mimetype;
212 QJsonObject json = loader.
metaData().value(
"MetaData").toObject();
213 Q_FOREACH(
const QString &mimetype, json.value(
"X-KDE-Export").toString().split(
",", Qt::SkipEmptyParts)) {
216 mimeTypes << mimetype;
233 QJsonObject json = loader.
metaData().value(
"MetaData").toObject();
234 QString directionKey = direction ==
Export ?
"X-KDE-Export" :
"X-KDE-Import";
236 if (json.value(directionKey).toString().split(
",", Qt::SkipEmptyParts).contains(mimetype)) {
238 KPluginFactory *factory = qobject_cast<KPluginFactory *>(loader.
instance());
246 if (!obj || !obj->inherits(
"KisImportExportFilter")) {
259 int w = json.value(
"X-KDE-Weight").toInt();
264 f->setObjectName(loader.
fileName());
290 if (!defaultDir.isEmpty()) {
291 dialog.setDefaultDir(defaultDir);
295 mimeTypes <<
"audio/mpeg";
296 mimeTypes <<
"audio/ogg";
297 mimeTypes <<
"audio/vorbis";
298 mimeTypes <<
"audio/vnd.wave";
299 mimeTypes <<
"audio/flac";
301 dialog.setMimeTypeFilters(mimeTypes);
302 dialog.setCaption(i18nc(
"@title:window",
"Open Audio"));
304 return dialog.filename();
313 dialog.setDirectoryUrl(QUrl(defaultUri));
314 dialog.setMimeTypeFilters(
QStringList(
"application/x-krita"));
316 return dialog.filename();
324 QString typeName = mimeType;
325 if (typeName.isEmpty()) {
336 d->cachedExportFilter &&
337 d->cachedExportFilterMimeType == typeName) {
339 filter =
d->cachedExportFilter;
344 if (direction ==
Export) {
345 d->cachedExportFilter = filter;
346 d->cachedExportFilterMimeType = typeName;
354 filter->setFilename(location);
355 filter->setRealFilename(realLocation);
357 filter->setMimeType(typeName);
359 if (direction ==
Import) {
361 filter->setImportUserFeedBackInterface(
new SynchronousUserFeedbackInterface(kisMain,
batchMode()));
364 if (!
d->updater.isNull()) {
372 filter->setUpdater(
d->updater);
376 if (direction ==
Export) {
378 to = typeName.toLatin1();
381 from = typeName.toLatin1();
390 if (direction ==
Import) {
392 KisUsageLogger::log(QString(
"Importing %1 to %2. Location: %3. Real location: %4. Batchmode: %5")
393 .arg(QString::fromLatin1(from), QString::fromLatin1(to), location,
394 realLocation, QString::number(
batchMode())));
404 result =
doImport(location, filter);
411 qWarning() <<
"Loaded a profile-less file without a fallback. Rejecting image "
416 "model: %6 %5 (%7). Layers: %8")
417 .arg(QString::fromLatin1(from), QString::number(image->
width()),
418 QString::number(image->
height()), QString::number(image->
xRes()),
422 QString::number(image->
nlayers())));
424 qWarning() <<
"The filter returned OK, but there is no image";
429 KisUsageLogger::log(QString(
"Failed to load image from %1").arg(QString::fromLatin1(from)));
434 if (!exportConfiguration) {
435 exportConfiguration = filter->lastSavedConfiguration(from, to);
438 if (exportConfiguration) {
442 bool alsoAsKra =
false;
446 &alsoAsKra, isAdvancedExporting);
455 "Converting from %1 to %2. Location: %3. Real location: %4. Batchmode: %5. Configuration: %6")
456 .arg(QString::fromLatin1(from), QString::fromLatin1(to), location, realLocation,
458 (exportConfiguration ? exportConfiguration->toXML() :
"none")));
463 exportConfiguration, alsoAsKraLocation));
471 exportConfiguration, alsoAsKraLocation));
473 result =
doExport(location, filter, exportConfiguration, alsoAsKraLocation);
476 if (exportConfiguration && !
batchMode()) {
487 const bool isThereAlpha =
495 (cs->
profile()->
name().contains(QLatin1String(
"srgb"), Qt::CaseInsensitive) &&
496 !cs->
profile()->
name().contains(QLatin1String(
"g10")));
509 static_cast<int>(primaries));
510 exportConfiguration->setProperty(
512 static_cast<int>(transferFunction));
525 const QByteArray &from,
526 const QByteArray &to,
527 const bool batchMode,
528 const bool showWarnings,
530 bool isAdvancedExporting)
546 errors = checker.
errors();
551 if (QThread::currentThread() == qApp->thread()) {
552 wdg = filter->createConfigurationWidget(0, from, to);
555 if (wdg && kisMain) {
563 warnings.append(i18nc(
"image conversion warning",
"The image contains <b>assistants</b>. The assistants will not be saved."));
566 warnings.append(i18nc(
"image conversion warning",
"The image contains <b>reference images</b>. The reference images will not be saved."));
569 warnings.append(i18nc(
"image conversion warning",
"The image contains <b>guides</b>. The guides will not be saved."));
572 warnings.append(i18nc(
"image conversion warning",
"The image contains a <b>custom grid configuration</b>. The configuration will not be saved."));
575 bool shouldFlattenTheImageBeforeScaling =
false;
577 if (isAdvancedExporting) {
578 QMap<QString, KisExportCheckBase *> exportChecks = filter->exportChecks();
580 const bool filterSupportsMultilayerExport =
581 exportChecks.contains(
"MultiLayerCheck") &&
585 if (!filterSupportsMultilayerExport) {
586 shouldFlattenTheImageBeforeScaling =
true;
589 shouldFlattenTheImageBeforeScaling =
true;
590 warnings.append(i18nc(
"image conversion warning",
"Trying to perform an Advanced Export with the image containing a <b>filter layer</b>. The image will be <b>flattened</b> before resizing."));
593 shouldFlattenTheImageBeforeScaling =
true;
594 warnings.append(i18nc(
"image conversion warning",
"Trying to perform an Advanced Export with the image containing a <b>filter mask</b>. The image will be <b>flattened</b> before resizing."));
596 bool hasLayerStyles =
599 KisLayer *layer = dynamic_cast<KisLayer*>(node.data());
600 return layer && layer->layerStyle();
603 if (hasLayerStyles) {
604 shouldFlattenTheImageBeforeScaling =
true;
605 warnings.append(i18nc(
"image conversion warning",
"Trying to perform an Advanced Export with the image containing a <b>layer style</b>. The image will be <b>flattened</b> before resizing."));
611 QString error =
"<html><body><p><b>"
612 + i18n(
"Error: cannot save this image as a %1.", mimeUserDescription)
613 +
"</b> " + i18n(
"Reasons:") +
"</p>"
615 Q_FOREACH(
const QString &w, errors) {
616 error +=
"\n<li>" + w +
"</li>";
621 QMessageBox::critical(
KisPart::instance()->currentMainwindow(), i18nc(
"@title:window",
"Krita: Export Error"), error);
625 if (!
batchMode && (wdg || !warnings.isEmpty() || isAdvancedExporting)) {
626 QWidget *page =
new QWidget();
627 QVBoxLayout *layout =
new QVBoxLayout(page);
629 if (showWarnings && !warnings.isEmpty()) {
630 QHBoxLayout *hLayout =
new QHBoxLayout();
632 QLabel *labelWarning =
new QLabel();
634 hLayout->addWidget(labelWarning);
638 bn->setText(i18nc(
"Keep the extra space at the end of the sentence, please",
"Warning: saving as a %1 will lose information from your image. ", mimeUserDescription));
639 bn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
641 hLayout->addWidget(bn);
643 layout->addLayout(hLayout);
645 QTextBrowser *browser =
new QTextBrowser();
646 browser->setMinimumWidth(bn->width());
649 QString warning =
"<html><body><p><b>"
650 + i18n(
"You will lose information when saving this image as a %1.", mimeUserDescription);
652 if (warnings.size() == 1) {
653 warning +=
"</b> " + i18n(
"Reason:") +
"</p>";
656 warning +=
"</b> " + i18n(
"Reasons:") +
"</p>";
658 warning +=
"<p/><ul>";
660 Q_FOREACH(
const QString &w, warnings) {
661 warning +=
"\n<li>" + w +
"</li>";
665 browser->setHtml(warning);
668 QTabWidget *box =
new QTabWidget;
671 box->addTab(wdg,i18n(
"Options"));
676 if (isAdvancedExporting) {
679 box->addTab(wdgImageSize,i18n(
"Resize"));
681 layout->addWidget(box);
683 QCheckBox *chkAlsoAsKra = 0;
684 if (showWarnings && !warnings.isEmpty()) {
685 chkAlsoAsKra =
new QCheckBox(i18n(
"Also save your image as a Krita file."));
686 chkAlsoAsKra->setChecked(
KisConfig(
true).readEntry<bool>(
"AlsoSaveAsKra",
false));
687 layout->addWidget(chkAlsoAsKra);
692 page->setParent(&dlg);
694 dlg.setWindowTitle(mimeUserDescription);
696 if (showWarnings || wdg || isAdvancedExporting) {
705 *alsoAsKra = chkAlsoAsKra->isChecked();
710 if (isAdvancedExporting && wdgImageSize) {
711 if (shouldFlattenTheImageBeforeScaling) {
734 QFile file(location);
735 if (!file.exists()) {
739 if (filter->supportsIO() && !file.open(QFile::ReadOnly)) {
755 const QString alsoAsKraLocation)
760 if (!alsoAsKraLocation.isNull() && status.
isOk()) {
768 filter->setFilename(alsoAsKraLocation);
771 filter->lastSavedConfiguration(mime, mime);
773 status =
doExportImpl(alsoAsKraLocation, filter, kraExportConfiguration);
790#if !(defined(Q_OS_WIN) || defined(Q_OS_MACOS))
797 QSaveFile file(location);
798 file.setDirectWriteFallback(
true);
799 if (filter->supportsIO() && !file.open(QFile::WriteOnly)) {
801 QFileInfo fi(location);
802 QTemporaryFile file(QDir::tempPath() +
"/.XXXXXX.kra");
803 if (filter->supportsIO() && !file.open()) {
805 QFileDevice::FileError error = file.error();
806 if (file.error() == QFileDevice::NoError) {
813 error = QFileDevice::OpenError;
817 file.cancelWriting();
824 if (filter->supportsIO()) {
825 if (!status.
isOk()) {
827 file.cancelWriting();
831 if (!file.commit()) {
832 qWarning() <<
"Could not commit QSaveFile";
843 if (!file.copy(location)) {
844 file.setAutoRemove(
false);
853 QString verificationResult = filter->verify(location);
854 if (!verificationResult.isEmpty()) {
869 return location +
".kra";
float value(const T *src, size_t ch)
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
QList< QString > QStringList
ColorPrimaries
The colorPrimaries enum Enum of colorants, follows ITU H.273 for values 0 to 255, and has extra known...
@ PRIMARIES_ADOBE_RGB_1998
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...
void writeEntry(const QString &name, const T &value)
void setExportConfiguration(const QString &filterId, KisPropertiesConfigurationSP properties) const
KisSharedPtr< KisReferenceImagesLayer > referenceImagesLayer() const
void setErrorMessage(const QString &errMsg)
static QByteArray nativeFormatMimeType()
QList< KisPaintingAssistantSP > assistants
bool fileBatchMode() const
KisGuidesConfig guidesConfig
const KoColorSpace * colorSpace() const
void flatten(KisNodeSP activeNode)
KisPaintDeviceSP projection() const
void scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy)
start asynchronous operation on scaling the image
The base class for import and export filters.
void setMimeType(const QString &mime)
static const QString ColorDepthIDTag
static const QString ColorModelIDTag
static const QString CICPTransferCharacteristicsTag
static const QString CICPPrimariesTag
static const QString ImageContainsTransparencyTag
static const QString sRGBTag
static const QString HDRTag
The class managing all the filters.
KisImportExportErrorCode importDocument(const QString &location, const QString &mimeType)
ConversionResult convert(Direction direction, const QString &location, const QString &realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration, bool isAsync, bool isAdvancedExporting=false)
KisImportExportErrorCode doExport(const QString &location, QSharedPointer< KisImportExportFilter > filter, KisPropertiesConfigurationSP exportConfiguration, const QString alsoAsKraLocation)
void setUpdater(KoUpdaterPtr updater)
QString getAlsoAsKraLocation(const QString location) const
QString cachedExportFilterMimeType
bool batchMode(void) const
QFuture< KisImportExportErrorCode > exportDocumentAsync(const QString &location, const QString &realLocation, const QByteArray &mimeType, KisImportExportErrorCode &status, bool showWarnings=true, KisPropertiesConfigurationSP exportConfiguration=0, bool isAdvancedExporting=false)
KisImportExportManager(KisDocument *document)
static QString getUriForAdditionalFile(const QString &defaultUri, QWidget *parent)
static QStringList m_exportMimeTypes
static QString askForAudioFileName(const QString &defaultDir, QWidget *parent)
static KisImportExportFilter * filterForMimeType(const QString &mimetype, Direction direction)
filterForMimeType loads the relevant import/export plugin and returns it. The caller is responsible f...
KisImportExportErrorCode exportDocument(const QString &location, const QString &realLocation, const QByteArray &mimeType, bool showWarnings=true, KisPropertiesConfigurationSP exportConfiguration=0, bool isAdvancedExporting=false)
Exports the given file/document to the specified URL/mimetype.
bool askUserAboutExportConfiguration(QSharedPointer< KisImportExportFilter > filter, KisPropertiesConfigurationSP exportConfiguration, const QByteArray &from, const QByteArray &to, bool batchMode, const bool showWarnings, bool *alsoAsKra, bool isAdvancedExporting=false)
~KisImportExportManager() override
KisImportExportErrorCode doExportImpl(const QString &location, QSharedPointer< KisImportExportFilter > filter, KisPropertiesConfigurationSP exportConfiguration)
static void fillStaticExportConfigurationProperties(KisPropertiesConfigurationSP exportConfiguration, KisImageSP image)
KisImportExportErrorCode doImport(const QString &location, QSharedPointer< KisImportExportFilter > filter)
QSharedPointer< KisImportExportFilter > cachedExportFilter
static QStringList m_importMimeTypes
A static cache for the availability checks of filters.
static QStringList supportedMimeTypes(Direction direction)
KisViewManager * viewManager
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
static QString descriptionForMimeType(const QString &mimeType)
Find the user-readable description for the given mimetype.
const KoColorSpace * colorSpace() const
static bool checkDeviceHasTransparency(KisPaintDeviceSP dev)
static KisPart * instance()
KisMainWindow * currentMainwindow() const
bool check(KisImageSP image, QMap< QString, KisExportCheckBase * > filterChecks)
check checks the image against the capabilities of the export filter
QStringList errors() const
QStringList warnings() const
static void log(const QString &message)
Logs with date/time.
virtual bool hasHighDynamicRange() const =0
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
A dialog base class with standard buttons and predefined layouts.
void setMainWidget(QWidget *widget)
void setButtons(ButtonCodes buttonMask)
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
static KoJsonTrader * instance()
QList< Plugin > query(const QString &servicetype, const QString &mimetype)
KisFilterStrategy * filterType()
double desiredResolution()
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
QSharedPointer< T > toQShared(T *ptr)
KisPinnedSharedPtr< KisPropertiesConfiguration > KisPropertiesConfigurationSP
KisSharedPtr< KisNode > KisNodeSP
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
QIcon loadIcon(const QString &name)
KisNodeSP recursiveFindNode(KisNodeSP node, std::function< bool(KisNodeSP)> func)
void forceAllDelayedNodesUpdate(KisNodeSP root)
KisImportExportErrorCode m_status
KisImportExportErrorCode status() const
QFuture< KisImportExportErrorCode > futureStatus() const
QFuture< KisImportExportErrorCode > m_futureStatus
ConversionResult(KisImportExportErrorCode status)
ConversionResult(const QFuture< KisImportExportErrorCode > &futureStatus)
void setStatus(KisImportExportErrorCode value)
virtual ColorPrimaries getColorPrimaries() const
getColorPrimaries
virtual TransferCharacteristics getTransferCharacteristics() const
getTransferCharacteristics This function should be subclassed at some point so we can get the value f...
QObject * instance() const
QJsonObject metaData() const
QString errorString() const