File indexing completed on 2024-12-22 04:10:23

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_paint_layer_test.h"
0008 #include <simpletest.h>
0009 #include <QImage>
0010 #include <QCoreApplication>
0011 
0012 #include <KoColorSpace.h>
0013 #include <KoColorSpaceRegistry.h>
0014 
0015 #include "kundo2command.h"
0016 
0017 #include "kis_group_layer.h"
0018 #include "kis_types.h"
0019 #include "kis_paint_layer.h"
0020 #include "kis_image.h"
0021 #include "kis_paint_device.h"
0022 #include "kis_transparency_mask.h"
0023 #include <testutil.h>
0024 #include "kis_selection.h"
0025 #include "kis_fill_painter.h"
0026 #include "kis_pixel_selection.h"
0027 #include <kis_iterator_ng.h>
0028 #include "kis_layer_projection_plane.h"
0029 #include "kis_psd_layer_style.h"
0030 #include "filter/kis_filter_registry.h"
0031 #include "kis_keyframe_channel.h"
0032 #include "kis_paint_device_debug_utils.h"
0033 
0034 void KisPaintLayerTest::testProjection()
0035 {
0036 
0037     QImage qimage(QString(FILES_DATA_DIR) + '/' + "hakonepa.png");
0038     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
0039     KisImageSP image = new KisImage(0, qimage.width(), qimage.height(), cs, "merge test");
0040 
0041     KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8);
0042     layer->paintDevice()->convertFromQImage(qimage, 0, 0, 0);
0043     image->addNode(layer.data());
0044 
0045     // Make sure the projection and the paint device are the same -- we don't have masks yet
0046     QVERIFY(layer->paintDevice().data() == layer->projection().data());
0047 
0048     KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(image, "tmask");
0049     transparencyMask->initSelection(layer);
0050     transparencyMask->selection()->pixelSelection()->invert();
0051     image->addNode(transparencyMask.data(), layer.data());
0052 
0053     // Now there are masks. Verify that
0054     Q_ASSERT(layer->hasEffectMasks());
0055 
0056     // And now we're going to update the projection, but nothing is dirty yet
0057     layer->projectionPlane()->recalculate(qimage.rect(), layer);
0058 
0059     // Which also means that the projection is no longer the paint device
0060     QVERIFY(layer->paintDevice().data() != layer->projection().data());
0061 
0062     // Now the machinery will start to roll
0063     layer->setDirty(qimage.rect());
0064 
0065     // And now we're going to update the projection, but nothing is dirty yet
0066     layer->projectionPlane()->recalculate(qimage.rect(), layer);
0067 
0068     // Which also means that the projection is no longer the paint device
0069     QVERIFY(layer->paintDevice().data() != layer->projection().data());
0070 
0071     // And the projection is no longer 0, because while we've updated it, nothing is dirty,
0072     // so nothing gets updated
0073     QVERIFY(layer->projection().data() != 0);
0074 
0075     // The selection is initially empty, so after an update, all pixels are still visible
0076     layer->projectionPlane()->recalculate(qimage.rect(), layer);
0077 
0078     // We've inverted the mask, so now nothing is seen
0079     KisSequentialConstIterator it(layer->projection(), qimage.rect());
0080     while (it.nextPixel()) {
0081         QVERIFY(cs->opacityU8(it.oldRawData()) == OPACITY_TRANSPARENT_U8);
0082     };
0083 
0084     // Now fill the layer with some opaque pixels
0085     transparencyMask->select(qimage.rect());
0086     transparencyMask->setDirty(qimage.rect());
0087     image->waitForDone();
0088 
0089     layer->projection()->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("aaa.png");
0090     // Nothing is transparent anymore, so the projection and the paint device should be identical again
0091     QPoint errpoint;
0092     if (!TestUtil::compareQImages(errpoint, qimage, layer->projection()->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) {
0093         QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
0094     }
0095 
0096 }
0097 
0098 void KisPaintLayerTest::testKeyframing()
0099 {
0100     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
0101     KisImageSP image = new KisImage(0, 512, 512, cs, "");
0102     KisPaintLayerSP layer = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8);
0103     KisPaintDeviceSP dev = layer->paintDevice();
0104 
0105     KisKeyframeChannel *contentChannel = layer->getKeyframeChannel(KisKeyframeChannel::Raster.id());
0106     QVERIFY(!contentChannel);
0107 
0108     layer->enableAnimation();
0109 
0110     contentChannel = layer->getKeyframeChannel("content", true);
0111     QVERIFY(contentChannel);
0112     QCOMPARE(contentChannel->keyframeCount(), 1);
0113 
0114     KUndo2Command parentCommand;
0115 
0116     contentChannel->addKeyframe(7, &parentCommand);
0117     QCOMPARE(contentChannel->keyframeCount(), 2);
0118     QVERIFY(contentChannel->keyframeAt(0) != contentChannel->keyframeAt(7));
0119 
0120     KisPaintLayerSP layerCopy = new KisPaintLayer(*layer.data());
0121 }
0122 
0123 void KisPaintLayerTest::testLayerStyles()
0124 {
0125     /**
0126      * FIXME: Right now the layer style plugin is stored in 'filters'
0127      *        directory, so we need to load filters to get it registered
0128      *        in the factory.
0129      */
0130     KisFilterRegistry::instance();
0131 
0132     const QRect imageRect(0, 0, 200, 200);
0133     const QRect rFillRect(10, 10, 100, 100);
0134     const QRect tMaskRect(50, 50, 20, 20);
0135     const QRect partialSelectionRect(90, 50, 20, 20);
0136 
0137 
0138     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
0139     KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "styles test");
0140 
0141     KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8);
0142     image->addNode(layer);
0143 
0144     layer->paintDevice()->fill(rFillRect, KoColor(Qt::red, cs));
0145 
0146     layer->setDirty();
0147     image->waitForDone();
0148     KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "00L_initial", "dd");
0149 
0150     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0151     style->dropShadow()->setNoise(30);
0152     style->dropShadow()->setEffectEnabled(true);
0153 
0154     layer->setLayerStyle(style);
0155 
0156     layer->setDirty();
0157     image->waitForDone();
0158     KIS_DUMP_DEVICE_2(image->projection(), imageRect, "02P_styled", "dd");
0159 
0160     KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(image, "tmask");
0161 
0162     KisSelectionSP selection = new KisSelection();
0163     selection->pixelSelection()->select(tMaskRect, OPACITY_OPAQUE_U8);
0164     transparencyMask->setSelection(selection);
0165     image->addNode(transparencyMask, layer);
0166 
0167     layer->setDirty();
0168     image->waitForDone();
0169     KIS_DUMP_DEVICE_2(image->projection(), imageRect, "03P_styled", "dd");
0170 
0171     selection->pixelSelection()->select(partialSelectionRect, OPACITY_OPAQUE_U8);
0172     layer->setDirty(partialSelectionRect);
0173 
0174     layer->setDirty();
0175     image->waitForDone();
0176     KIS_DUMP_DEVICE_2(image->projection(), imageRect, "04P_partial", "dd");
0177 }
0178 
0179 
0180 SIMPLE_TEST_MAIN(KisPaintLayerTest)