File indexing completed on 2024-05-19 04:32:39
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __QIMAGE_BASED_TEST_H 0008 #define __QIMAGE_BASED_TEST_H 0009 0010 #ifndef USE_DOCUMENT 0011 #define USE_DOCUMENT 1 0012 #endif /* USE_DOCUMENT */ 0013 0014 #include <testutil.h> 0015 0016 0017 #include <KoColorSpace.h> 0018 #include <KoColorSpaceRegistry.h> 0019 0020 #include <KoShapeContainer.h> 0021 #include <KoShapeRegistry.h> 0022 #include <KoShapeFactoryBase.h> 0023 0024 #if USE_DOCUMENT 0025 #include "KisDocument.h" 0026 #include "kis_shape_layer.h" 0027 #endif /* USE_DOCUMENT */ 0028 0029 #include "kis_undo_stores.h" 0030 #include "kis_image.h" 0031 #include "kis_selection.h" 0032 #include "kis_default_bounds.h" 0033 #include "KisImageResolutionProxy.h" 0034 #include "kis_paint_layer.h" 0035 #include "kis_adjustment_layer.h" 0036 #include "kis_transparency_mask.h" 0037 #include "kis_clone_layer.h" 0038 #include <KisGlobalResourcesInterface.h> 0039 0040 #include "filter/kis_filter.h" 0041 #include "filter/kis_filter_registry.h" 0042 #include "kis_filter_configuration.h" 0043 0044 #include "commands/kis_selection_commands.h" 0045 0046 0047 namespace TestUtil 0048 { 0049 0050 class QImageBasedTest 0051 { 0052 public: 0053 QImageBasedTest(const QString &directoryName) 0054 : m_directoryName(directoryName) 0055 { 0056 } 0057 0058 // you need to declare your own test function 0059 // See KisProcessingTest for example 0060 0061 protected: 0062 0063 /** 0064 * Creates a complex image connected to a surrogate undo store 0065 */ 0066 KisImageSP createImage(KisSurrogateUndoStore *undoStore) { 0067 QImage sourceImage(fetchDataFileLazy("hakonepa.png")); 0068 0069 QRect imageRect = QRect(QPoint(0,0), sourceImage.size()); 0070 0071 QRect transpRect(50,50,300,300); 0072 QRect blurRect(66,66,300,300); 0073 QPoint blurShift(34,34); 0074 QPoint cloneShift(75,75); 0075 0076 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0077 KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "merge test"); 0078 0079 KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); 0080 Q_ASSERT(filter); 0081 KisFilterConfigurationSP configuration = filter->defaultConfiguration(KisGlobalResourcesInterface::instance()); 0082 Q_ASSERT(configuration); 0083 0084 /** 0085 * HACK ALERT: before this commit a07ef143f6 the meaning of 0086 * 'strength' was different. After that, to make the tests 0087 * run correctly we should manually set the old value (it is 0088 * not available via GUI anymore). 0089 */ 0090 configuration->setProperty("strength", 500); 0091 0092 KisAdjustmentLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration->cloneWithResourcesSnapshot(), 0); 0093 blur1->internalSelection()->clear(); 0094 blur1->internalSelection()->pixelSelection()->select(blurRect); 0095 blur1->setX(blurShift.x()); 0096 blur1->setY(blurShift.y()); 0097 0098 KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); 0099 paintLayer1->paintDevice()->convertFromQImage(sourceImage, 0, 0, 0); 0100 0101 KisCloneLayerSP cloneLayer1 = 0102 new KisCloneLayer(paintLayer1, image, "clone1", OPACITY_OPAQUE_U8); 0103 cloneLayer1->setX(cloneShift.x()); 0104 cloneLayer1->setY(cloneShift.y()); 0105 0106 image->addNode(cloneLayer1); 0107 image->addNode(blur1); 0108 image->addNode(paintLayer1); 0109 0110 KisTransparencyMaskSP transparencyMask1 = new KisTransparencyMask(image, "tmask1"); 0111 transparencyMask1->testingInitSelection(transpRect, paintLayer1); 0112 0113 image->addNode(transparencyMask1, paintLayer1); 0114 0115 return image; 0116 } 0117 0118 /** 0119 * Creates a simple image with one empty layer and connects it to 0120 * a surrogate undo store 0121 */ 0122 KisImageSP createTrivialImage(KisSurrogateUndoStore *undoStore) { 0123 QRect imageRect = QRect(0, 0, 640, 441); 0124 0125 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0126 KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "merge test"); 0127 0128 KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); 0129 image->addNode(paintLayer1); 0130 0131 return image; 0132 } 0133 0134 void addGlobalSelection(KisImageSP image) { 0135 QRect selectionRect(40,40,300,300); 0136 0137 KisSelectionSP selection = new KisSelection(new KisDefaultBounds(image), toQShared(new KisImageResolutionProxy(image))); 0138 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0139 pixelSelection->select(selectionRect); 0140 0141 KUndo2Command *cmd = new KisSetGlobalSelectionCommand(image, selection); 0142 image->undoAdapter()->addCommand(cmd); 0143 } 0144 0145 #if USE_DOCUMENT 0146 0147 void addShapeLayer(KisDocument *doc, KisImageSP image) { 0148 0149 KisShapeLayerSP shapeLayer = new KisShapeLayer(doc->shapeController(), image.data(), "shape", OPACITY_OPAQUE_U8); 0150 image->addNode(shapeLayer); 0151 0152 KoShapeFactoryBase *f1 = KoShapeRegistry::instance()->get("StarShape"); 0153 KoShapeFactoryBase *f2 = KoShapeRegistry::instance()->get("RectangleShape"); 0154 0155 KoShape *shape1 = f1->createDefaultShape(); 0156 KoShape *shape2 = f2->createDefaultShape(); 0157 0158 shape1->setPosition(QPointF(100,100)); 0159 shape2->setPosition(QPointF(200,200)); 0160 0161 shapeLayer->addShape(shape1); 0162 shapeLayer->addShape(shape2); 0163 0164 QApplication::processEvents(); 0165 } 0166 0167 #endif /* USE_DOCUMENT*/ 0168 0169 bool checkLayersInitial(KisImageWSP image, int baseFuzzyness = 0) { 0170 QString prefix = "initial_with_selection"; 0171 QString prefix2 = findNode(image->root(), "shape") ? "_with_shape" : ""; 0172 return checkLayers(image, prefix + prefix2, baseFuzzyness); 0173 } 0174 0175 bool checkLayersInitialRootOnly(KisImageWSP image, int baseFuzzyness = 0) { 0176 QString prefix = "initial_with_selection"; 0177 QString prefix2 = findNode(image->root(), "shape") ? "_with_shape" : ""; 0178 return checkLayers(image, prefix + prefix2, baseFuzzyness, false); 0179 } 0180 0181 /** 0182 * Checks the content of image's layers against the set of 0183 * QImages stored in @p prefix subfolder 0184 */ 0185 bool checkLayers(KisImageWSP image, const QString &prefix, int baseFuzzyness = 0, bool recursive = true) { 0186 QVector<QImage> images; 0187 QVector<QString> names; 0188 0189 fillNamesImages(image->root(), image->bounds(), images, names, recursive); 0190 0191 bool valid = true; 0192 0193 const int stackSize = images.size(); 0194 for(int i = 0; i < stackSize; i++) { 0195 if(!checkOneQImage(images[i], prefix, names[i], baseFuzzyness)) { 0196 valid = false; 0197 } 0198 } 0199 0200 return valid; 0201 } 0202 0203 /** 0204 * Checks the content of one image's layer against the QImage 0205 * stored in @p prefix subfolder 0206 */ 0207 bool checkOneLayer(KisImageWSP image, KisNodeSP node, const QString &prefix, int baseFuzzyness = 0) { 0208 QVector<QImage> images; 0209 QVector<QString> names; 0210 0211 fillNamesImages(node, image->bounds(), images, names); 0212 0213 return checkOneQImage(images.first(), prefix, names.first(), baseFuzzyness); 0214 } 0215 0216 // add default bounds param 0217 bool checkOneDevice(KisPaintDeviceSP device, 0218 const QString &prefix, 0219 const QString &name, 0220 int baseFuzzyness = 0) 0221 { 0222 QImage image = device->convertToQImage(0); 0223 return checkOneQImage(image, prefix, name, baseFuzzyness); 0224 } 0225 0226 KisNodeSP findNode(KisNodeSP root, const QString &name) { 0227 return TestUtil::findNode(root, name); 0228 } 0229 0230 private: 0231 bool checkOneQImage(const QImage &image, 0232 const QString &prefix, 0233 const QString &name, 0234 int baseFuzzyness) 0235 { 0236 QString realName = prefix + "_" + name + ".png"; 0237 QString expectedName = prefix + "_" + name + "_expected.png"; 0238 0239 bool valid = true; 0240 0241 QString fullPath = fetchDataFileLazy(m_directoryName + '/' + 0242 prefix + '/' + realName); 0243 0244 if (fullPath.isEmpty()) { 0245 // Try without the testname subdirectory 0246 fullPath = fetchDataFileLazy(prefix + '/' + 0247 realName); 0248 } 0249 0250 if (fullPath.isEmpty()) { 0251 // Try without the prefix subdirectory 0252 fullPath = fetchDataFileLazy(m_directoryName + '/' + 0253 realName); 0254 } 0255 0256 QImage ref(fullPath); 0257 0258 QPoint temp; 0259 int fuzzy = baseFuzzyness; 0260 0261 { 0262 QStringList terms = name.split('_'); 0263 if(terms[0] == "root" || 0264 terms[0] == "blur1" || 0265 terms[0] == "shape") { 0266 0267 fuzzy++; 0268 } 0269 } 0270 0271 if(ref != image && 0272 !TestUtil::compareQImages(temp, ref, image, fuzzy, fuzzy)) { 0273 0274 0275 dbgKrita << "--- Wrong image:" << realName; 0276 valid = false; 0277 0278 image.save(QString(FILES_OUTPUT_DIR) + '/' + realName); 0279 ref.save(QString(FILES_OUTPUT_DIR) + '/' + expectedName); 0280 } 0281 0282 return valid; 0283 } 0284 0285 void fillNamesImages(KisNodeSP node, const QRect &rc, 0286 QVector<QImage> &images, 0287 QVector<QString> &names, 0288 bool recursive = true) { 0289 0290 while (node) { 0291 if(node->paintDevice()) { 0292 names.append(node->name() + "_paintDevice"); 0293 images.append(node->paintDevice()-> 0294 convertToQImage(0, rc.x(), rc.y(), 0295 rc.width(), rc.height())); 0296 } 0297 0298 if(node->original() && node->original() != node->paintDevice()) { 0299 names.append(node->name() + "_original"); 0300 images.append(node->original()-> 0301 convertToQImage(0, rc.x(), rc.y(), 0302 rc.width(), rc.height())); 0303 } 0304 0305 if(node->projection() && node->projection() != node->paintDevice()) { 0306 names.append(node->name() + "_projection"); 0307 images.append(node->projection()-> 0308 convertToQImage(0, rc.x(), rc.y(), 0309 rc.width(), rc.height())); 0310 } 0311 0312 if (recursive) { 0313 fillNamesImages(node->firstChild(), rc, images, names); 0314 } 0315 node = node->nextSibling(); 0316 } 0317 } 0318 0319 private: 0320 QString m_directoryName; 0321 0322 }; 0323 0324 } 0325 0326 #endif /* __QIMAGE_BASED_TEST_H */