File indexing completed on 2024-12-22 04:08:46

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_gbr_brush_test.h"
0008 
0009 #include <simpletest.h>
0010 #include <QString>
0011 #include <QDir>
0012 #include <KoColor.h>
0013 #include <KoColorSpace.h>
0014 #include <KoColorSpaceRegistry.h>
0015 #include <testutil.h>
0016 #include "../kis_gbr_brush.h"
0017 #include "kis_types.h"
0018 #include "kis_paint_device.h"
0019 #include "brushengine/kis_paint_information.h"
0020 #include <kis_fixed_paint_device.h>
0021 #include "kis_qimage_pyramid.h"
0022 #include <KisGlobalResourcesInterface.h>
0023 
0024 void KisGbrBrushTest::testMaskGenerationSingleColor()
0025 {
0026     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "brush.gbr"));
0027     brush->load(KisGlobalResourcesInterface::instance());
0028     Q_ASSERT(brush->valid());
0029     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0030 
0031     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0032 
0033     // check masking an existing paint device
0034     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
0035     fdev->setRect(QRect(0, 0, 100, 100));
0036     fdev->initialize();
0037     cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100);
0038 
0039     // Check creating a mask dab with a single color
0040     fdev = new KisFixedPaintDevice(cs);
0041     brush->mask(fdev, KoColor(Qt::black, cs), KisDabShape(), info);
0042 
0043     QPoint errpoint;
0044     QImage result = QImage(QString(FILES_DATA_DIR) + '/' + "result_brush_3.png");
0045     QImage image = fdev->convertToQImage(0);
0046     if (!TestUtil::compareQImages(errpoint, image, result)) {
0047         image.save("kis_gbr_brush_test_3.png");
0048         QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
0049     }
0050 }
0051 
0052 void KisGbrBrushTest::testMaskGenerationDevColor()
0053 {
0054     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "brush.gbr"));
0055     brush->load(KisGlobalResourcesInterface::instance());
0056     Q_ASSERT(brush->valid());
0057     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0058 
0059     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0060 
0061     // check masking an existing paint device
0062     KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
0063     fdev->setRect(QRect(0, 0, 100, 100));
0064     fdev->initialize();
0065     cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100);
0066 
0067     // Check creating a mask dab with a color taken from a paint device
0068     KoColor red(Qt::red, cs);
0069     cs->setOpacity(red.data(), quint8(128), 1);
0070     KisPaintDeviceSP dev = new KisPaintDevice(cs);
0071     dev->fill(0, 0, 100, 100, red.data());
0072 
0073     fdev = new KisFixedPaintDevice(cs);
0074     brush->mask(fdev, dev, KisDabShape(), info);
0075 
0076     QPoint errpoint;
0077     QImage result = QImage(QString(FILES_DATA_DIR) + '/' + "result_brush_4.png");
0078     QImage image = fdev->convertToQImage(0);
0079     if (!TestUtil::compareQImages(errpoint, image, result)) {
0080         image.save("kis_gbr_brush_test_4.png");
0081         QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
0082     }
0083 }
0084 
0085 void KisGbrBrushTest::testImageGeneration()
0086 {
0087     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "testing_brush_512_bars.gbr"));
0088     bool res = brush->load(KisGlobalResourcesInterface::instance());
0089     Q_UNUSED(res);
0090     Q_ASSERT(res);
0091     QVERIFY(!brush->brushTipImage().isNull());
0092     qsrand(1);
0093 
0094     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0095     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0096     KisFixedPaintDeviceSP dab;
0097 
0098     for (int i = 0; i < 200; i++) {
0099         qreal scale = qreal(qrand()) / RAND_MAX * 2.0;
0100         qreal rotation = qreal(qrand()) / RAND_MAX * 2 * M_PI;
0101         qreal subPixelX = qreal(qrand()) / RAND_MAX * 0.5;
0102         QString testName =
0103             QString("brush_%1_sc_%2_rot_%3_sub_%4")
0104             .arg(i).arg(scale).arg(rotation).arg(subPixelX);
0105 
0106         dab = brush->paintDevice(cs, KisDabShape(scale, 1.0, rotation), info, subPixelX);
0107 
0108         /**
0109          * Compare first 10 images. Others are tested for asserts only
0110          */
0111         if (i < 10) {
0112             QImage result = dab->convertToQImage(0);
0113             TestUtil::checkQImage(result, "brush_masks", "", testName);
0114         }
0115     }
0116 }
0117 
0118 #include "kis_qimage_pyramid.h"
0119 
0120 void KisGbrBrushTest::benchmarkPyramidCreation()
0121 {
0122     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "testing_brush_512_bars.gbr"));
0123     brush->load(KisGlobalResourcesInterface::instance());
0124     QVERIFY(!brush->brushTipImage().isNull());
0125 
0126     QBENCHMARK {
0127         KisQImagePyramid pyramid(brush->brushTipImage());
0128         qreal temp = 0.0;
0129         QVERIFY(!pyramid.getClosest(QTransform(), &temp).isNull()); // avoid compiler elimination of unused code!
0130     }
0131 }
0132 
0133 void KisGbrBrushTest::benchmarkScaling()
0134 {
0135     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "testing_brush_512_bars.gbr"));
0136     brush->load(KisGlobalResourcesInterface::instance());
0137     QVERIFY(!brush->brushTipImage().isNull());
0138     qsrand(1);
0139 
0140     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0141     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0142     KisFixedPaintDeviceSP dab;
0143 
0144     {
0145         // warm up the pyramid!
0146         dab = brush->paintDevice(cs, KisDabShape(qreal(qrand()) / RAND_MAX * 2.0, 1.0, 0.0), info);
0147         QVERIFY(dab); // avoid compiler elimination of unused code!
0148         dab.clear();
0149     }
0150 
0151     QBENCHMARK {
0152         dab = brush->paintDevice(cs, KisDabShape(qreal(qrand()) / RAND_MAX * 2.0, 1.0, 0.0), info);
0153         //dab->convertToQImage(0).save(QString("dab_%1_new_smooth.png").arg(i++));
0154     }
0155 }
0156 
0157 void KisGbrBrushTest::benchmarkRotation()
0158 {
0159     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "testing_brush_512_bars.gbr"));
0160     brush->load(KisGlobalResourcesInterface::instance());
0161     QVERIFY(!brush->brushTipImage().isNull());
0162     qsrand(1);
0163 
0164     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0165     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0166     KisFixedPaintDeviceSP dab;
0167 
0168     QBENCHMARK {
0169         dab = brush->paintDevice(cs, KisDabShape(1.0, 1.0, qreal(qrand()) / RAND_MAX * 2 * M_PI), info);
0170     }
0171 }
0172 
0173 void KisGbrBrushTest::benchmarkMaskScaling()
0174 {
0175     QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + '/' + "testing_brush_512_bars.gbr"));
0176     brush->load(KisGlobalResourcesInterface::instance());
0177     QVERIFY(!brush->brushTipImage().isNull());
0178     qsrand(1);
0179 
0180     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
0181     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
0182     KisFixedPaintDeviceSP dab = new KisFixedPaintDevice(cs);
0183 
0184     QBENCHMARK {
0185         KoColor c(Qt::black, cs);
0186         qreal scale = qreal(qrand()) / RAND_MAX * 2.0;
0187         brush->mask(dab, c, KisDabShape(scale, 1.0, 0.0), info, 0.0, 0.0, 1.0);
0188     }
0189 }
0190 
0191 void KisGbrBrushTest::testPyramidLevelRounding()
0192 {
0193     QSize imageSize(41, 41);
0194     QImage image(imageSize, QImage::Format_ARGB32);
0195     image.fill(0);
0196 
0197     KisQImagePyramid pyramid(image);
0198 
0199     qreal baseScale;
0200     int baseLevel;
0201 
0202     baseLevel = pyramid.findNearestLevel(1.0, &baseScale);
0203     QCOMPARE(baseScale, 1.0);
0204     QCOMPARE(baseLevel, 3);
0205 
0206     baseLevel = pyramid.findNearestLevel(2.0, &baseScale);
0207     QCOMPARE(baseScale, 2.0);
0208     QCOMPARE(baseLevel, 2);
0209 
0210     baseLevel = pyramid.findNearestLevel(4.0, &baseScale);
0211     QCOMPARE(baseScale, 4.0);
0212     QCOMPARE(baseLevel, 1);
0213 
0214     baseLevel = pyramid.findNearestLevel(0.5, &baseScale);
0215     QCOMPARE(baseScale, 0.5);
0216     QCOMPARE(baseLevel, 4);
0217 
0218     baseLevel = pyramid.findNearestLevel(0.25, &baseScale);
0219     QCOMPARE(baseScale, 0.25);
0220     QCOMPARE(baseLevel, 5);
0221 
0222     baseLevel = pyramid.findNearestLevel(0.25 + 1e-7, &baseScale);
0223     QCOMPARE(baseScale, 0.25);
0224     QCOMPARE(baseLevel, 5);
0225 }
0226 
0227 static QSize dabTransformHelper(KisDabShape const& shape)
0228 {
0229     QSize const testSize(150, 150);
0230     qreal const subPixelX = 0.0,
0231                 subPixelY = 0.0;
0232     return KisQImagePyramid::imageSize(testSize, shape, subPixelX, subPixelY);
0233 }
0234 
0235 void KisGbrBrushTest::testPyramidDabTransform()
0236 {
0237     QCOMPARE(dabTransformHelper(KisDabShape(1.0, 1.0, 0.0)),      QSize(150, 150));
0238     QCOMPARE(dabTransformHelper(KisDabShape(1.0, 0.5, 0.0)),      QSize(150,  75));
0239     QCOMPARE(dabTransformHelper(KisDabShape(1.0, 1.0, M_PI / 4)), QSize(213, 213));
0240     QCOMPARE(dabTransformHelper(KisDabShape(1.0, 0.5, M_PI / 4)), QSize(160, 160));
0241 }
0242 
0243 // see comment in KisQImagePyramid::appendPyramidLevel
0244 void KisGbrBrushTest::testQPainterTransformationBorder()
0245 {
0246     QImage image1(10, 10, QImage::Format_ARGB32);
0247     QImage image2(12, 12, QImage::Format_ARGB32);
0248 
0249     image1.fill(0);
0250     image2.fill(0);
0251 
0252     {
0253         QPainter gc(&image1);
0254         gc.fillRect(QRect(0, 0, 10, 10), Qt::black);
0255     }
0256 
0257     {
0258         QPainter gc(&image2);
0259         gc.fillRect(QRect(1, 1, 10, 10), Qt::black);
0260     }
0261 
0262     image1.save("src1.png");
0263     image2.save("src2.png");
0264 
0265     {
0266         QImage canvas(100, 100, QImage::Format_ARGB32);
0267         canvas.fill(0);
0268         QPainter gc(&canvas);
0269         QTransform transform;
0270         transform.rotate(15);
0271         gc.setTransform(transform);
0272         gc.setRenderHints(QPainter::SmoothPixmapTransform);
0273         gc.drawImage(QPointF(50, 50), image1);
0274         gc.end();
0275         canvas.save("canvas1.png");
0276     }
0277     {
0278         QImage canvas(100, 100, QImage::Format_ARGB32);
0279         canvas.fill(0);
0280         QPainter gc(&canvas);
0281         QTransform transform;
0282         transform.rotate(15);
0283         gc.setTransform(transform);
0284         gc.setRenderHints(QPainter::SmoothPixmapTransform);
0285         gc.drawImage(QPointF(50, 50), image2);
0286         gc.end();
0287         canvas.save("canvas2.png");
0288     }
0289 }
0290 
0291 SIMPLE_TEST_MAIN(KisGbrBrushTest)