File indexing completed on 2024-06-09 04:22:15
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_selection_test.h" 0008 #include <simpletest.h> 0009 0010 0011 #include <kis_debug.h> 0012 #include <QRect> 0013 0014 #include <KoColorSpace.h> 0015 #include <KoColorSpaceRegistry.h> 0016 #include <KoCompositeOpRegistry.h> 0017 0018 #include "kis_datamanager.h" 0019 #include "kis_pixel_selection.h" 0020 #include "kis_selection.h" 0021 #include "kis_default_bounds.h" 0022 #include "KisImageResolutionProxy.h" 0023 #include "kis_fill_painter.h" 0024 #include "kis_mask.h" 0025 #include "kis_image.h" 0026 #include "kis_transparency_mask.h" 0027 #include <testutil.h> 0028 #include "testimage.h" 0029 #include <KoColorModelStandardIds.h> 0030 0031 void KisSelectionTest::testGrayColorspaceConversion() 0032 { 0033 const KoColorSpace *csA = 0034 KoColorSpaceRegistry::instance()-> 0035 colorSpace(GrayAColorModelID.id(), 0036 Integer8BitsColorDepthID.id(), 0037 QString()); 0038 0039 const KoColorSpace *csNoA = 0040 KoColorSpaceRegistry::instance()->alpha8(); 0041 0042 QVERIFY(csA); 0043 QVERIFY(csNoA); 0044 0045 QCOMPARE(csA->pixelSize(), 2U); 0046 QCOMPARE(csNoA->pixelSize(), 1U); 0047 0048 quint8 color1[1] = {128}; 0049 quint8 color2[2] = {64,32}; 0050 0051 csA->convertPixelsTo(color2, color1, csNoA, 1, 0052 KoColorConversionTransformation::internalRenderingIntent(), 0053 KoColorConversionTransformation::internalConversionFlags()); 0054 0055 QCOMPARE((int)color1[0], 8); 0056 0057 csNoA->convertPixelsTo(color1, color2, csA, 1, 0058 KoColorConversionTransformation::internalRenderingIntent(), 0059 KoColorConversionTransformation::internalConversionFlags()); 0060 0061 QCOMPARE((int)color2[0], 8); 0062 QCOMPARE((int)color2[1], 255); 0063 } 0064 0065 void KisSelectionTest::testGrayColorspaceOverComposition() 0066 { 0067 const KoColorSpace *csA = 0068 KoColorSpaceRegistry::instance()-> 0069 colorSpace(GrayAColorModelID.id(), 0070 Integer8BitsColorDepthID.id(), 0071 QString()); 0072 const KoColorSpace *csNoA = 0073 KoColorSpaceRegistry::instance()->alpha8(); 0074 0075 QVERIFY(csA); 0076 QVERIFY(csNoA); 0077 0078 QCOMPARE(csA->pixelSize(), 2U); 0079 QCOMPARE(csNoA->pixelSize(), 1U); 0080 0081 quint8 color0[2] = {32,255}; 0082 quint8 color1[2] = {128,64}; 0083 quint8 color3[1] = {32}; 0084 0085 KoCompositeOp::ParameterInfo params; 0086 params.dstRowStart = color0; 0087 params.dstRowStride = 0; 0088 params.srcRowStart = color1; 0089 params.srcRowStride = 0; 0090 params.maskRowStart = 0; 0091 params.maskRowStride = 0; 0092 params.rows = 1; 0093 params.cols = 1; 0094 params.opacity = 1.0; 0095 params.flow = 1.0; 0096 0097 csA->bitBlt(csA, params, csA->compositeOp(COMPOSITE_OVER), 0098 KoColorConversionTransformation::internalRenderingIntent(), 0099 KoColorConversionTransformation::internalConversionFlags()); 0100 0101 QCOMPARE((int)color0[0], 56); 0102 QCOMPARE((int)color0[1], 255); 0103 0104 params.dstRowStart = color3; 0105 0106 csNoA->bitBlt(csA, params, csNoA->compositeOp(COMPOSITE_OVER), 0107 KoColorConversionTransformation::internalRenderingIntent(), 0108 KoColorConversionTransformation::internalConversionFlags()); 0109 0110 QCOMPARE((int)color3[0], 56); 0111 } 0112 0113 void KisSelectionTest::testSelectionComponents() 0114 { 0115 KisSelectionSP selection = new KisSelection(); 0116 0117 QCOMPARE(selection->hasNonEmptyPixelSelection(), false); 0118 QCOMPARE(selection->hasNonEmptyShapeSelection(), false); 0119 QCOMPARE(selection->shapeSelection(), (void*)0); 0120 0121 selection->pixelSelection()->select(QRect(10,10,10,10)); 0122 QCOMPARE(selection->hasNonEmptyPixelSelection(), true); 0123 QCOMPARE(selection->selectedExactRect(), QRect(10,10,10,10)); 0124 } 0125 0126 void KisSelectionTest::testSelectionActions() 0127 { 0128 KisSelectionSP selection = new KisSelection(); 0129 QVERIFY(selection->hasNonEmptyPixelSelection() == false); 0130 QVERIFY(selection->hasNonEmptyShapeSelection() == false); 0131 0132 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0133 pixelSelection->select(QRect(0, 0, 20, 20)); 0134 0135 KisPixelSelectionSP tmpSel = new KisPixelSelection(); 0136 tmpSel->select(QRect(10, 0, 20, 20)); 0137 0138 pixelSelection->applySelection(tmpSel, SELECTION_ADD); 0139 QCOMPARE(pixelSelection->selectedExactRect(), QRect(0, 0, 30, 20)); 0140 QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 30, 20)); 0141 0142 pixelSelection->clear(); 0143 pixelSelection->select(QRect(0, 0, 20, 20)); 0144 0145 pixelSelection->applySelection(tmpSel, SELECTION_SUBTRACT); 0146 QCOMPARE(pixelSelection->selectedExactRect(), QRect(0, 0, 10, 20)); 0147 QCOMPARE(selection->selectedExactRect(), QRect(0, 0, 10, 20)); 0148 0149 pixelSelection->clear(); 0150 pixelSelection->select(QRect(0, 0, 20, 20)); 0151 0152 pixelSelection->applySelection(tmpSel, SELECTION_INTERSECT); 0153 QCOMPARE(pixelSelection->selectedExactRect(), QRect(10, 0, 10, 20)); 0154 QCOMPARE(selection->selectedExactRect(), QRect(10, 0, 10, 20)); 0155 } 0156 0157 void KisSelectionTest::testInvertSelection() 0158 { 0159 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0160 KisImageSP image = new KisImage(0, 1024, 1024, cs, "stest"); 0161 0162 KisSelectionSP selection = new KisSelection(new KisDefaultBounds(image), toQShared(new KisImageResolutionProxy(image))); 0163 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0164 pixelSelection->select(QRect(20, 20, 20, 20)); 0165 0166 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), MAX_SELECTED); 0167 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MIN_SELECTED); 0168 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 512, 512), MIN_SELECTED); 0169 QCOMPARE(pixelSelection->selectedExactRect(), QRect(20, 20, 20, 20)); 0170 0171 pixelSelection->invert(); 0172 0173 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 100, 100), MAX_SELECTED); 0174 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 22, 22), MIN_SELECTED); 0175 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MAX_SELECTED); 0176 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 512, 512), MAX_SELECTED); 0177 QCOMPARE(pixelSelection->selectedExactRect(), QRect(0,0,1024,1024)); 0178 QCOMPARE(pixelSelection->selectedRect(), QRect(0,0,1024,1024)); 0179 0180 selection->updateProjection(); 0181 0182 QCOMPARE(selection->selectedExactRect(), QRect(0,0,1024,1024)); 0183 QCOMPARE(selection->selectedRect(), QRect(0,0,1024,1024)); 0184 0185 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 100, 100), MAX_SELECTED); 0186 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 22, 22), MIN_SELECTED); 0187 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 10, 10), MAX_SELECTED); 0188 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 0, 0), MAX_SELECTED); 0189 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 512, 512), MAX_SELECTED); 0190 } 0191 0192 void KisSelectionTest::testInvertSelectionSemi() 0193 { 0194 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0195 KisImageSP image = new KisImage(0, 1024, 1024, cs, "stest"); 0196 0197 KisSelectionSP selection = new KisSelection(new KisDefaultBounds(image), toQShared(new KisImageResolutionProxy(image))); 0198 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0199 quint8 selectedness = 42; 0200 pixelSelection->select(QRect(20, 20, 20, 20), selectedness); 0201 0202 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), selectedness); 0203 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MIN_SELECTED); 0204 QCOMPARE(pixelSelection->selectedExactRect(), QRect(20, 20, 20, 20)); 0205 0206 pixelSelection->invert(); 0207 0208 quint8 invertedSelectedness = MAX_SELECTED - selectedness; 0209 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 30, 30), invertedSelectedness); 0210 QCOMPARE(TestUtil::alphaDevicePixel(pixelSelection, 0, 0), MAX_SELECTED); 0211 QCOMPARE(pixelSelection->selectedExactRect(), QRect(0,0,1024,1024)); 0212 QCOMPARE(pixelSelection->selectedRect(), QRect(0,0,1024,1024)); 0213 0214 selection->updateProjection(); 0215 0216 QCOMPARE(selection->selectedExactRect(), QRect(0,0,1024,1024)); 0217 QCOMPARE(selection->selectedRect(), QRect(0,0,1024,1024)); 0218 0219 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 30, 30), invertedSelectedness); 0220 QCOMPARE(TestUtil::alphaDevicePixel(selection->projection(), 0, 0), MAX_SELECTED); 0221 } 0222 0223 void KisSelectionTest::testCopy() 0224 { 0225 KisSelectionSP sel = new KisSelection(); 0226 sel->pixelSelection()->select(QRect(10, 10, 200, 200), 128); 0227 0228 sel->updateProjection(); 0229 0230 KisSelectionSP sel2 = new KisSelection(*sel.data()); 0231 QCOMPARE(sel2->selectedExactRect(), sel->selectedExactRect()); 0232 0233 QPoint errpoint; 0234 if (!TestUtil::comparePaintDevices(errpoint, sel->projection(), sel2->projection())) { 0235 sel2->projection()->convertToQImage(0, 0, 0, 200, 200).save("merge_visitor6.png"); 0236 QFAIL(QString("Failed to copy selection, first different pixel: %1,%2 ") 0237 .arg(errpoint.x()) 0238 .arg(errpoint.y()) 0239 .toLatin1()); 0240 } 0241 } 0242 0243 void KisSelectionTest::testSelectionExactBounds() 0244 { 0245 QRect referenceImageRect(0,0,1000,1000); 0246 QRect referenceDeviceRect(100,100,1040,1040); 0247 0248 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0249 0250 KisImageSP image = new KisImage(0, referenceImageRect.width(), 0251 referenceImageRect.height(), 0252 cs, "stest"); 0253 0254 KisPaintDeviceSP device = new KisPaintDevice(cs); 0255 device->setDefaultBounds(new KisDefaultBounds(image)); 0256 device->fill(referenceDeviceRect, KoColor(Qt::white, cs)); 0257 0258 QCOMPARE(device->exactBounds(), referenceDeviceRect); 0259 0260 KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(device), toQShared(new KisImageResolutionProxy(image))); 0261 0262 quint8 defaultPixel = MAX_SELECTED; 0263 selection->pixelSelection()->setDefaultPixel(KoColor(&defaultPixel, selection->pixelSelection()->colorSpace())); 0264 0265 // the selection uses device's extent only for performance reasons 0266 // \see bug 320213 0267 QCOMPARE(selection->selectedExactRect(), device->extent() | referenceImageRect); 0268 } 0269 0270 void KisSelectionTest::testSetParentNodeAfterCreation() 0271 { 0272 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0273 KisImageSP image = new KisImage(0, 100, 100, cs, "stest"); 0274 KisSelectionSP selection = new KisSelection(); 0275 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0276 0277 QCOMPARE(selection->parentNode(), KisNodeWSP(0)); 0278 QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(0)); 0279 0280 selection->setParentNode(image->root()); 0281 0282 QCOMPARE(selection->parentNode(), KisNodeWSP(image->root())); 0283 QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(image->root())); 0284 } 0285 0286 void KisSelectionTest::testSetParentNodeBeforeCreation() 0287 { 0288 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); 0289 KisImageSP image = new KisImage(0, 100, 100, cs, "stest"); 0290 KisSelectionSP selection = new KisSelection(); 0291 0292 selection->setParentNode(image->root()); 0293 0294 KisPixelSelectionSP pixelSelection = selection->pixelSelection(); 0295 0296 QCOMPARE(selection->parentNode(), KisNodeWSP(image->root())); 0297 QCOMPARE(selection->pixelSelection()->parentNode(), KisNodeWSP(image->root())); 0298 } 0299 0300 void KisSelectionTest::testOutlineGeneration() 0301 { 0302 KisSelectionSP sel = new KisSelection(); 0303 sel->pixelSelection()->select(QRect(428,436, 430,211), 128); 0304 0305 QVERIFY(sel->outlineCacheValid()); 0306 0307 QPainterPath originalOutline = sel->outlineCache(); 0308 0309 sel->pixelSelection()->invalidateOutlineCache(); 0310 sel->recalculateOutlineCache(); 0311 0312 QPainterPath calculatedOutline = sel->outlineCache(); 0313 0314 QPainterPath closedSubPath = calculatedOutline; 0315 closedSubPath.closeSubpath(); 0316 0317 /** 0318 * Our outline generation code has a small problem: it can 0319 * generate a polygon, which isn't closed (it'll repeat the first 0320 * point instead). There is a special workaround for it in 0321 * KisPixelSelection::recalculateOutlineCache(), which explicitly 0322 * closes the path, so here we just check it. 0323 */ 0324 0325 bool isClosed = closedSubPath == calculatedOutline; 0326 QVERIFY(isClosed); 0327 } 0328 0329 KISTEST_MAIN(KisSelectionTest) 0330 0331