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