File indexing completed on 2025-03-09 04:09:44

0001 /*
0002  * SPDX-FileCopyrightText: 2009 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_psd_test.h"
0008 
0009 
0010 #include <simpletest.h>
0011 #include <QCoreApplication>
0012 
0013 #include <testui.h>
0014 
0015 #include "filestest.h"
0016 
0017 #ifndef FILES_DATA_DIR
0018 #error "FILES_DATA_DIR not set. A directory with the data used for testing the importing of files in krita"
0019 #endif
0020 
0021 #include <resources/KoPattern.h>
0022 #include "kis_group_layer.h"
0023 #include "kis_psd_layer_style.h"
0024 #include "kis_paint_device_debug_utils.h"
0025 #include <KisImportExportErrorCode.h>
0026 #include <kis_generator_layer.h>
0027 #include <kis_filter_configuration.h>
0028 #include <KisGlobalResourcesInterface.h>
0029 
0030 
0031 
0032 const QString PSDMimetype = "image/vnd.adobe.photoshop";
0033 
0034 
0035 void KisPSDTest::testFiles()
0036 {
0037     QStringList exclusions;
0038     exclusions << "100x100indexed.psd";
0039     exclusions << "100x100rgb16.psd";
0040     exclusions << "100x100cmyk16.psd";
0041     exclusions << "100x100cmyk8.psd";
0042     exclusions << "gray.psd";
0043     exclusions << "vector.psd";
0044     exclusions << "masks.psd";
0045     exclusions << "angle2.psd";
0046     exclusions << "diamond2.psd";
0047     exclusions << "linear3.psd";
0048     exclusions << "cmyk8-pantone_solid_coated_688c-L51_a33_b-8.psd";
0049     exclusions << "pattern2_uncompressed.psd";
0050     exclusions << "pattern4_rle.psd";
0051 
0052 
0053     TestUtil::testFiles(QString(FILES_DATA_DIR) + "/sources", exclusions, QString(), 2);
0054 }
0055 
0056 void KisPSDTest::testOpening()
0057 {
0058     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "testing_psd_ls.psd");
0059 
0060     QScopedPointer<KisDocument> doc(qobject_cast<KisDocument*>(KisPart::instance()->createDocument()));
0061 
0062     KisImportExportManager manager(doc.data());
0063     doc->setFileBatchMode(true);
0064 
0065     KisImportExportErrorCode status = manager.importDocument(sourceFileInfo.absoluteFilePath(), QString());
0066     QVERIFY(status.isOk());
0067 
0068     Q_ASSERT(doc->image());
0069 }
0070 
0071 QSharedPointer<KisDocument> openPsdDocument(const QFileInfo &fileInfo)
0072 {
0073     QSharedPointer<KisDocument> doc(qobject_cast<KisDocument*>(KisPart::instance()->createDocument()));
0074 
0075     KisImportExportManager manager(doc.data());
0076     doc->setFileBatchMode(true);
0077 
0078     KisImportExportErrorCode status = manager.importDocument(fileInfo.absoluteFilePath(), QString());
0079     Q_UNUSED(status);
0080 
0081     return doc;
0082 }
0083 
0084 void KisPSDTest::testTransparencyMask()
0085 {
0086     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "sources/masks.psd");
0087 
0088     Q_ASSERT(sourceFileInfo.exists());
0089 
0090     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0091     QVERIFY(doc->image());
0092 
0093     QImage result = doc->image()->projection()->convertToQImage(0, doc->image()->bounds());
0094     QVERIFY(TestUtil::checkQImageExternal(result, "psd_test", "transparency_masks", "kiki_single", 1, 1));
0095 
0096 
0097     doc->setFileBatchMode(true);
0098     doc->setMimeType("image/vnd.adobe.photoshop");
0099 
0100     QFileInfo dstFileInfo(QDir::currentPath() + '/' + "test_tmask.psd");
0101     bool retval = doc->exportDocumentSync(dstFileInfo.absoluteFilePath(), "image/vnd.adobe.photoshop");
0102     QVERIFY(retval);
0103 
0104     {
0105         QSharedPointer<KisDocument> doc = openPsdDocument(dstFileInfo);
0106         QVERIFY(doc->image());
0107 
0108         QImage result = doc->image()->projection()->convertToQImage(0, doc->image()->bounds());
0109         QVERIFY(TestUtil::checkQImageExternal(result, "psd_test", "transparency_masks", "kiki_single", 1, 1));
0110 
0111         QVERIFY(doc->image()->root()->lastChild());
0112         QVERIFY(doc->image()->root()->lastChild()->firstChild());
0113         QVERIFY(doc->image()->root()->lastChild()->firstChild()->inherits("KisTransparencyMask"));
0114     }
0115 }
0116 
0117 void KisPSDTest::testOpenGrayscaleMultilayered()
0118 {
0119     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "sources/gray.psd");
0120     //QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "sources/100x100gray8.psd");
0121 
0122     Q_ASSERT(sourceFileInfo.exists());
0123 
0124     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0125     QVERIFY(doc->image());
0126 }
0127 
0128 void KisPSDTest::testOpenGroupLayers()
0129 {
0130     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "group_layers.psd");
0131 
0132     Q_ASSERT(sourceFileInfo.exists());
0133 
0134     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0135     QVERIFY(doc->image());
0136 
0137     KisNodeSP node = TestUtil::findNode(doc->image()->root(), "Group 1 PT");
0138     KisGroupLayer *group = dynamic_cast<KisGroupLayer*>(node.data());
0139     QVERIFY(group);
0140 
0141     QVERIFY(group->passThroughMode());
0142 }
0143 
0144 void KisPSDTest::testOpenLayerStyles()
0145 {
0146     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "testing_psd_ls.psd");
0147 
0148     Q_ASSERT(sourceFileInfo.exists());
0149 
0150     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0151     QVERIFY(doc->image());
0152 
0153     KisLayerSP layer = qobject_cast<KisLayer*>(doc->image()->root()->lastChild().data());
0154     QVERIFY(layer->layerStyle());
0155     QVERIFY(layer->layerStyle()->dropShadow());
0156     QVERIFY(layer->layerStyle()->dropShadow()->effectEnabled());
0157 }
0158 
0159 void KisPSDTest::testOpenFillLayers()
0160 {
0161     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "sources/angle2.psd");
0162 
0163         Q_ASSERT(sourceFileInfo.exists());
0164 
0165         QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0166         QVERIFY(doc->image());
0167         KisGeneratorLayerSP layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0168         QVERIFY(layer);
0169         QVERIFY(layer->filter()->name() == "gradient");
0170         QVERIFY(layer->filter()->getDouble("end_position_angle") == 180);
0171         QVERIFY(layer->filter()->getDouble("end_position_distance") == 50);
0172         QVERIFY(layer->filter()->getString("shape") == "conical");
0173 
0174         QFileInfo sourceFileInfo2(QString(FILES_DATA_DIR) + '/' + "sources/diamond2.psd");
0175 
0176         Q_ASSERT(sourceFileInfo2.exists());
0177 
0178         doc = openPsdDocument(sourceFileInfo2);
0179         QVERIFY(doc->image());
0180         layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0181         QVERIFY(layer);
0182         QVERIFY(layer->filter()->name() == "gradient");
0183         QVERIFY(layer->filter()->getDouble("end_position_angle") == 16.5);
0184         QVERIFY(layer->filter()->getDouble("end_position_distance") - double(40.2306) < 0.001);
0185         QVERIFY(layer->filter()->getString("shape") == "square");
0186 
0187         QFileInfo sourceFileInfo3(QString(FILES_DATA_DIR) + '/' + "sources/linear3.psd");
0188 
0189         Q_ASSERT(sourceFileInfo3.exists());
0190 
0191         doc = openPsdDocument(sourceFileInfo3);
0192         QVERIFY(doc->image());
0193         layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0194         QVERIFY(layer);
0195         QVERIFY(layer->filter()->name() == "gradient");
0196         QVERIFY(layer->filter()->getDouble("end_position_angle") == 270);
0197         QVERIFY(layer->filter()->getString("shape") == "linear");
0198 
0199         QFileInfo sourceFileInfo4(QString(FILES_DATA_DIR) + '/' + "sources/cmyk8-pantone_solid_coated_688c-L51_a33_b-8.psd");
0200 
0201         Q_ASSERT(sourceFileInfo4.exists());
0202 
0203         doc = openPsdDocument(sourceFileInfo4);
0204         QVERIFY(doc->image());
0205         layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0206         QVERIFY(layer);
0207         QVERIFY(layer->filter()->name() == "color");
0208         KoColor c = layer->filter()->getColor("color");
0209         KoColor l = KoColor::fromXML("<color channeldepth='U16'><Lab space='"+KoColorSpaceRegistry::instance()->lab16()->name()+"' L='51.0' a='33.0' b='-8.0' /></color>");
0210         c.convertTo(l.colorSpace());
0211         QVERIFY(doc->image()->colorSpace()->difference(c.data(), l.data()) < 3);
0212         QVERIFY(c.metadata().value("spotName", QVariant()).toString() == "PANTONE 688 C");
0213         QVERIFY(c.metadata().value("psdSpotBook", QVariant()).toString().contains("Solid Coated"));
0214         QVERIFY(c.metadata().value("psdSpotBookId", QVariant()).toInt() == 3060);
0215 
0216         QFileInfo sourceFileInfo5(QString(FILES_DATA_DIR) + '/' + "sources/pattern2_uncompressed.psd");
0217 
0218         Q_ASSERT(sourceFileInfo5.exists());
0219 
0220         doc = openPsdDocument(sourceFileInfo5);
0221         QVERIFY(doc->image());
0222         layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0223         QVERIFY(layer);
0224         QVERIFY(layer->filter()->name() == "pattern");
0225         if (layer) {
0226             const QString patternMD5 = layer->filter()->getString("md5", "");
0227             const QString patternNameTemp = layer->filter()->getString("pattern", "Grid01.pat");
0228             const QString patternFileName = layer->filter()->getString("fileName", "");
0229 
0230             KoResourceLoadResult res = KisGlobalResourcesInterface::instance()->source(ResourceType::Patterns).bestMatchLoadResult(patternMD5, patternFileName, patternNameTemp);
0231             QVERIFY(res.resource<KoPattern>());
0232         }
0233         QVERIFY(layer->filter()->getDouble("transform_rotation_z") - 30.85 < 0.001);
0234         QVERIFY(layer->filter()->getDouble("transform_scale_x") - 3.63 < 0.001);
0235         QVERIFY(layer->filter()->getDouble("transform_scale_y") - 3.63 < 0.001);
0236 
0237         QFileInfo sourceFileInfo6(QString(FILES_DATA_DIR) + '/' + "sources/pattern4_rle.psd");
0238 
0239         Q_ASSERT(sourceFileInfo6.exists());
0240 
0241         doc = openPsdDocument(sourceFileInfo6);
0242         QVERIFY(doc->image());
0243         layer = qobject_cast<KisGeneratorLayer*>(doc->image()->root()->lastChild().data());
0244         QVERIFY(layer);
0245         QVERIFY(layer->filter()->name() == "pattern");
0246         if (layer) {
0247             const QString patternMD5 = layer->filter()->getString("md5", "");
0248             const QString patternNameTemp = layer->filter()->getString("pattern", "Grid01.pat");
0249             const QString patternFileName = layer->filter()->getString("fileName", "");
0250 
0251             KoResourceLoadResult res = KisGlobalResourcesInterface::instance()->source(ResourceType::Patterns).bestMatchLoadResult(patternMD5, patternFileName, patternNameTemp);
0252             QVERIFY(res.resource<KoPattern>());
0253         }
0254 }
0255 
0256 void KisPSDTest::testOpenLayerStylesWithPattern()
0257 {
0258     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "test_ls_pattern.psd");
0259 
0260     Q_ASSERT(sourceFileInfo.exists());
0261 
0262     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0263     QVERIFY(doc->image());
0264 
0265     KisLayerSP layer = qobject_cast<KisLayer*>(doc->image()->root()->lastChild().data());
0266     QVERIFY(layer->layerStyle());
0267     QVERIFY(layer->layerStyle()->patternOverlay());
0268     QVERIFY(layer->layerStyle()->patternOverlay()->effectEnabled());
0269 
0270     KoPatternSP pattern =
0271         layer->layerStyle()->patternOverlay()->pattern(
0272                 layer->layerStyle()->resourcesInterface());
0273 
0274     QVERIFY(pattern);
0275     QVERIFY(pattern->valid());
0276 }
0277 
0278 void KisPSDTest::testOpenLayerStylesWithPatternMulti()
0279 {
0280     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "test_ls_pattern_multi.psd");
0281 
0282     Q_ASSERT(sourceFileInfo.exists());
0283 
0284     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0285     QVERIFY(doc->image());
0286 
0287     KisLayerSP layer = qobject_cast<KisLayer*>(doc->image()->root()->lastChild().data());
0288     QVERIFY(layer->layerStyle());
0289 
0290     QVERIFY(layer->layerStyle()->patternOverlay());
0291     QVERIFY(layer->layerStyle()->patternOverlay()->effectEnabled());
0292     {
0293         KoPatternSP pattern =
0294             layer->layerStyle()->patternOverlay()->pattern(
0295                     layer->layerStyle()->resourcesInterface());
0296 
0297         QVERIFY(pattern);
0298         QVERIFY(pattern->valid());
0299     }
0300 
0301     QVERIFY(layer->layerStyle()->stroke());
0302     QVERIFY(layer->layerStyle()->stroke()->effectEnabled());
0303     {
0304         KoPatternSP pattern =
0305             layer->layerStyle()->stroke()->pattern(
0306                 layer->layerStyle()->resourcesInterface());
0307 
0308         QVERIFY(pattern);
0309         QVERIFY(pattern->valid());
0310     }
0311 }
0312 
0313 void KisPSDTest::testSaveLayerStylesWithPatternMulti()
0314 {
0315     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "test_ls_pattern_multi.psd");
0316 
0317     Q_ASSERT(sourceFileInfo.exists());
0318 
0319     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0320     QVERIFY(doc->image());
0321 
0322     KisLayerSP layer = qobject_cast<KisLayer*>(doc->image()->root()->lastChild().data());
0323     QVERIFY(layer->layerStyle());
0324 
0325     QVERIFY(layer->layerStyle()->patternOverlay());
0326     QVERIFY(layer->layerStyle()->patternOverlay()->effectEnabled());
0327     {
0328         KoPatternSP pattern =
0329             layer->layerStyle()->patternOverlay()->pattern(
0330                     layer->layerStyle()->resourcesInterface());
0331 
0332         QVERIFY(pattern);
0333         QVERIFY(pattern->valid());
0334     }
0335 
0336     QVERIFY(layer->layerStyle()->stroke());
0337     QVERIFY(layer->layerStyle()->stroke()->effectEnabled());
0338     {
0339         KoPatternSP pattern =
0340             layer->layerStyle()->stroke()->pattern(
0341                     layer->layerStyle()->resourcesInterface());
0342 
0343         QVERIFY(pattern);
0344         QVERIFY(pattern->valid());
0345     }
0346 
0347     doc->setFileBatchMode(true);
0348     const QByteArray mimeType("image/vnd.adobe.photoshop");
0349     QFileInfo dstFileInfo(QDir::currentPath() + '/' + "test_save_styles.psd");
0350     bool retval = doc->exportDocumentSync(dstFileInfo.absoluteFilePath(), mimeType);
0351     QVERIFY(retval);
0352 
0353     {
0354         QSharedPointer<KisDocument> doc = openPsdDocument(dstFileInfo);
0355         QVERIFY(doc->image());
0356 
0357         QImage result = doc->image()->projection()->convertToQImage(0, doc->image()->bounds());
0358         //QVERIFY(TestUtil::checkQImageExternal(result, "psd_test", "transparency_masks", "kiki_single"));
0359 
0360         KisLayerSP layer = qobject_cast<KisLayer*>(doc->image()->root()->lastChild().data());
0361         QVERIFY(layer->layerStyle());
0362 
0363         QVERIFY(layer->layerStyle()->patternOverlay());
0364         QVERIFY(layer->layerStyle()->patternOverlay()->effectEnabled());
0365         {
0366             KoPatternSP pattern =
0367                 layer->layerStyle()->patternOverlay()->pattern(
0368                         layer->layerStyle()->resourcesInterface());
0369 
0370             QVERIFY(pattern);
0371             QVERIFY(pattern->valid());
0372         }
0373 
0374         QVERIFY(layer->layerStyle()->stroke());
0375         QVERIFY(layer->layerStyle()->stroke()->effectEnabled());
0376         {
0377             KoPatternSP pattern =
0378                 layer->layerStyle()->stroke()->pattern(
0379                         layer->layerStyle()->resourcesInterface());
0380 
0381             QVERIFY(pattern);
0382             QVERIFY(pattern->valid());
0383         }
0384     }
0385 
0386 }
0387 
0388 void KisPSDTest::testOpeningFromOpenCanvas()
0389 {
0390     QFileInfo sourceFileInfo(QString(FILES_DATA_DIR) + '/' + "test_krita_psd_from_opencanvas.psd");
0391 
0392     Q_ASSERT(sourceFileInfo.exists());
0393 
0394     QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0395     QVERIFY(doc->image());
0396     QVERIFY(doc->image()->root()->firstChild());
0397 }
0398 
0399 void KisPSDTest::testOpeningAllFormats()
0400 {
0401     QString path = TestUtil::fetchExternalDataFileName("psd_format_test_files");
0402     QDir dirSources(path);
0403 
0404     if (path.isEmpty()) {
0405         qWarning() << "External folder is not present, skipping...";
0406         return;
0407     }
0408 
0409     bool shouldFailTheTest = false;
0410 
0411     Q_FOREACH (QFileInfo sourceFileInfo, dirSources.entryInfoList()) {
0412         Q_ASSERT(sourceFileInfo.exists());
0413 
0414         if (sourceFileInfo.isHidden() || sourceFileInfo.isDir()) {
0415             continue;
0416         }
0417 
0418         if (sourceFileInfo.fileName() != "ml_cmyk_16b.psd") {
0419             //continue;
0420         }
0421 
0422         //dbgKrita << "Opening" << ppVar(sourceFileInfo.fileName());
0423 
0424         QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0425 
0426         if (!doc->image()) {
0427             /**
0428              * 32bit images are expected to fail atm, their loading is not implemented
0429              */
0430             if (!sourceFileInfo.fileName().contains("_32b")) {
0431                 shouldFailTheTest = true;
0432             }
0433 
0434             errKrita << "FAILED to open" << sourceFileInfo.fileName();
0435             continue;
0436         }
0437 
0438         // just check visually if the file loads fine
0439         KIS_DUMP_DEVICE_2(doc->image()->projection(), QRect(0,0,100,100), sourceFileInfo.fileName(), "dd");
0440     }
0441 
0442     QVERIFY(!shouldFailTheTest);
0443 }
0444 
0445 void KisPSDTest::testSavingAllFormats()
0446 {
0447     QString path = TestUtil::fetchExternalDataFileName("psd_format_test_files");
0448     QDir dirSources(path);
0449 
0450     if (path.isEmpty()) {
0451         qWarning() << "External folder is not present, skipping...";
0452         return;
0453     }
0454 
0455     Q_FOREACH (QFileInfo sourceFileInfo, dirSources.entryInfoList()) {
0456         Q_ASSERT(sourceFileInfo.exists());
0457 
0458         if (sourceFileInfo.isHidden() || sourceFileInfo.isDir()) {
0459             continue;
0460         }
0461 
0462         if (sourceFileInfo.fileName() != "sl_rgb_8b.psd") {
0463             //continue;
0464         }
0465 
0466         dbgKrita << "Opening" << ppVar(sourceFileInfo.fileName());
0467 
0468         QSharedPointer<KisDocument> doc = openPsdDocument(sourceFileInfo);
0469 
0470         if (!doc->image()) {
0471             errKrita << "FAILED to open" << sourceFileInfo.fileName();
0472             continue;
0473         }
0474 
0475         QString baseName = sourceFileInfo.fileName();
0476 
0477         //QString originalName = QString("%1_0orig").arg(baseName);
0478         //QString resultName = QString("%1_1result").arg(baseName);
0479         QString tempPsdName = QString("%1_3interm.psd").arg(baseName);
0480 
0481         QImage refImage = doc->image()->projection()->convertToQImage(0, QRect(0,0,100,100));
0482 
0483         // uncomment to do a visual check
0484         // KIS_DUMP_DEVICE_2(doc->image()->projection(), QRect(0,0,100,100), originalName, "dd");
0485 
0486         doc->setFileBatchMode(true);
0487         doc->setMimeType("image/vnd.adobe.photoshop");
0488 
0489         QFileInfo dstFileInfo(QDir::currentPath() + '/' + tempPsdName);
0490 
0491         dbgKrita << "Saving" << ppVar(dstFileInfo.fileName());
0492 
0493         bool retval = doc->exportDocumentSync(dstFileInfo.absoluteFilePath(), "image/vnd.adobe.photoshop");
0494         QVERIFY(retval);
0495 
0496         {
0497             QSharedPointer<KisDocument> doc = openPsdDocument(dstFileInfo);
0498             QVERIFY(doc->image());
0499 
0500             // uncomment to do a visual check
0501             //KIS_DUMP_DEVICE_2(doc->image()->projection(), QRect(0,0,100,100), resultName, "dd");
0502 
0503             QImage resultImage = doc->image()->projection()->convertToQImage(0, QRect(0,0,100,100));
0504             QCOMPARE(resultImage, refImage);
0505         }
0506     }
0507 }
0508 
0509 
0510 
0511 void KisPSDTest::testImportFromWriteonly()
0512 {
0513     TestUtil::testImportFromWriteonly(PSDMimetype);
0514 }
0515 
0516 
0517 void KisPSDTest::testExportToReadonly()
0518 {
0519     TestUtil::testExportToReadonly(PSDMimetype);
0520 }
0521 
0522 
0523 void KisPSDTest::testImportIncorrectFormat()
0524 {
0525     TestUtil::testImportIncorrectFormat(PSDMimetype);
0526 }
0527 
0528 
0529 
0530 
0531 KISTEST_MAIN(KisPSDTest)
0532