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 */