void KisTransparencyMaskTest::testMoveMaskItself()
{
    KisImageSP image;
    KisPaintLayerSP layer;
    KisPaintDeviceSP dev;
    KisTransparencyMaskSP mask;

    initImage(image, layer, dev, mask);
    mask->initSelection(layer);
    mask->selection()->pixelSelection()->invert();
    mask->select(QRect(50, 50, 100, 100));

    KisFullRefreshWalker walker(image->bounds());
    KisAsyncMerger merger;

    walker.collectRects(layer, image->bounds());
    merger.startMerge(walker);

    // image->projection()->convertToQImage(0, 0,0,300,300).save("proj_before.png");

    QRect initialRect(0,0,200,100);
    QCOMPARE(layer->exactBounds(), initialRect);
    QCOMPARE(image->projection()->exactBounds(), QRect(50,50,100,50));


    //layer->setX(100);
    //layer->setY(100);

    dbgKrita << "Sel. rect before:" << mask->selection()->selectedExactRect();

    mask->setX(50);
    mask->setY(25);

    dbgKrita << "Sel. rect after:" << mask->selection()->selectedExactRect();


    QCOMPARE(mask->selection()->selectedExactRect(), QRect(100, 75, 100, 100));
    QCOMPARE(layer->paintDevice()->exactBounds(), initialRect);
    QCOMPARE(layer->projection()->exactBounds(), QRect(50, 50, 100, 50));

    dbgKrita << "";

    QRect updateRect(0,0,300,300);

    walker.collectRects(mask, updateRect);
    merger.startMerge(walker);

    // image->projection()->convertToQImage(0, 0,0,300,300).save("proj_after.png");

    QCOMPARE(layer->paintDevice()->exactBounds(), initialRect);
    QCOMPARE(layer->projection()->exactBounds(), QRect(100, 75, 100, 25));
}
void KisAsyncMergerTest::debugObligeChild()
{
    const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, 640, 441, colorSpace, "merger test");

    QImage sourceImage1(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png");
    KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace);
    device1->convertFromQImage(sourceImage1, 0, 0, 0);

    KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1);
    KisLayerSP groupLayer = new KisGroupLayer(image, "group", OPACITY_OPAQUE_U8);

    image->addNode(groupLayer, image->rootLayer());
    image->addNode(paintLayer1, groupLayer);

    QRect testRect1(0,0,640,441);
    QRect cropRect(image->bounds());

    KisMergeWalker walker(cropRect);
    KisAsyncMerger merger;

    walker.collectRects(paintLayer1, testRect1);
    merger.startMerge(walker);

    KisLayerSP rootLayer = image->rootLayer();
    QVERIFY(rootLayer->original() == groupLayer->projection());
    QVERIFY(groupLayer->original() == paintLayer1->projection());
}
void KisPrescaledProjectionTest::benchmarkUpdate()
{
    QImage referenceImage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png");
    QRect imageRect = QRect(QPoint(0,0), referenceImage.size());

    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "projection test");

    // set up 300dpi
    image->setResolution(300 / 72 , 300 / 72);

    KisPaintLayerSP layer = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, cs);
    layer->paintDevice()->convertFromQImage(referenceImage, 0);

    image->addNode(layer, image->rootLayer(), 0);

    KisPrescaledProjection projection;

    KisCoordinatesConverter converter;
    converter.setImage(image);
    projection.setCoordinatesConverter(&converter);
    projection.setMonitorProfile(0,
                                 KoColorConversionTransformation::internalRenderingIntent(),
                                 KoColorConversionTransformation::internalConversionFlags());
    projection.setImage(image);

    // Emulate "Use same aspect as pixels"
    converter.setResolution(image->xRes(), image->yRes());

    converter.setZoom(1.0);

    KisUpdateInfoSP info = projection.updateCache(image->bounds());
    projection.recalculateCache(info);

    QCOMPARE(imageRect, QRect(0,0,512,512));

    QRect dirtyRect(0,0,20,20);
    const qint32 numShifts = 25;
    const QPoint offset(dirtyRect.width(),dirtyRect.height());

    //CALLGRIND_START_INSTRUMENTATION;

    QBENCHMARK {
        for(qint32 i = 0; i < numShifts; i++) {
            KisUpdateInfoSP tempInfo = projection.updateCache(dirtyRect);
            projection.recalculateCache(tempInfo);

            dirtyRect.translate(offset);
        }
    }

    //CALLGRIND_STOP_INSTRUMENTATION;

}
Exemple #4
0
    bool pickWrapped(KisPaintDeviceSP dev, QPoint pos, KoColor *color, KisImageSP image)
    {
        if (!image->tryBarrierLock()) return false;

        if (image->wrapAroundModePermitted()) {
            pos = KisWrappedRect::ptToWrappedPt(pos, image->bounds());
        }

        bool result = pick(dev, pos, color);

        image->unlock();
        return result;
    }
void KisAsyncMergerTest::testSubgraphingWithoutUpdatingParent()
{
    const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, 128, 128, colorSpace, "clones test");

    KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace);
    device1->fill(image->bounds(), KoColor(Qt::white, colorSpace));
    KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1);

    KisPaintDeviceSP device2 = new KisPaintDevice(colorSpace);
    device2->fill(image->bounds(), KoColor(Qt::black, colorSpace));
    KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", 128, device2);

    image->addNode(paintLayer1, image->rootLayer());
    image->addNode(paintLayer2, image->rootLayer());

    image->initialRefreshGraph();

    QImage refImage(QString(FILES_DATA_DIR) + QDir::separator() + "subgraphing_without_updating.png");

    {
        QImage resultImage = image->projection()->convertToQImage(0);
        QCOMPARE(resultImage, refImage);
    }

    QRect cropRect(image->bounds());

    KisRefreshSubtreeWalker walker(cropRect);
    KisAsyncMerger merger;

    walker.collectRects(paintLayer2, image->bounds());
    merger.startMerge(walker);

    {
        QImage resultImage = image->projection()->convertToQImage(0);
        QCOMPARE(resultImage, refImage);
    }
}
void KisImageLayerMoveCommand::undo()
{
    KisImageSP image = m_image.toStrongRef();
    if (!image) {
        return;
    }
    image->moveNode(m_layer, m_prevParent, m_prevAbove);

    if (m_doUpdates) {
        image->refreshGraphAsync(m_newParent);
        if (m_newParent != m_prevParent) {
            m_layer->setDirty(image->bounds());
        }
    }
}
void KisRecalculateTransformMaskJob::run()
{
    /**
     * The mask might have been deleted from the layers stack. In
     * such a case, don't try do update it.
     */
    if (!m_mask->parent()) return;

    m_mask->recaclulateStaticImage();

    KisLayerSP layer = dynamic_cast<KisLayer*>(m_mask->parent().data());

    if (!layer) {
        warnKrita << "WARNING: KisRecalculateTransformMaskJob::run() Mask has no parent layer! Skipping projection update!";
        return;
    }

    KisImageSP image = layer->image();
    Q_ASSERT(image);

    image->requestProjectionUpdateNoFilthy(layer, layer->extent(), image->bounds());
}
 KUndo2Command* paint() {
     KisSelectionSP selection = m_image->globalSelection();
     KisSelectionTransaction transaction(QString(), m_image->undoAdapter(), selection);
     selection->getOrCreatePixelSelection()->select(m_image->bounds());
     return transaction.endAndTake();
 }
bool doPartialTests(const QString &prefix, KisImageSP image, KisLayerSP paintLayer,
                    KisLayerSP visibilityToggleLayer, KisTransformMaskSP mask)
{
    TestUtil::ExternalImageChecker chk(prefix, "transform_mask_updates");

    bool result = true;

    QRect refRect = image->bounds();

    int testIndex = 1;
    QString testName;

    for (int y = 0; y < refRect.height(); y += 512) {
        for (int x = 0; x < refRect.width(); x += 512) {
            QRect rc(x, y, 512, 512);

            if (rc.right() > refRect.right()) {
                rc.setRight(refRect.right());
                if (rc.isEmpty()) continue;
            }

            if (rc.bottom() > refRect.bottom()) {
                rc.setBottom(refRect.bottom());
                if (rc.isEmpty()) continue;
            }

            paintLayer->setDirty(rc);
            image->waitForDone();
            testName = QString("tm_%1_partial_%2_%3").arg(testIndex++).arg(x).arg(y);
            result &= chk.checkImage(image, testName);
        }
    }

    // initial update of the mask to clear the unused portions of the projection
    // (it updates only when we call set dirty on the mask itself, which happens
    // in Krita right after the addition of the mask onto a layer)

    mask->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_initial_mask_visible_on").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    // start layer visibility testing

    paintLayer->setVisible(false);
    paintLayer->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_layer_visible_off").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    paintLayer->setVisible(true);
    paintLayer->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_layer_visible_on").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    if (paintLayer != visibilityToggleLayer) {
        visibilityToggleLayer->setVisible(false);
        visibilityToggleLayer->setDirty();
        image->waitForDone();
        testName = QString("tm_%1_extra_layer_visible_off").arg(testIndex++);
        result &= chk.checkImage(image, testName);


        visibilityToggleLayer->setVisible(true);
        visibilityToggleLayer->setDirty();
        image->waitForDone();
        testName = QString("tm_%1_extra_layer_visible_on").arg(testIndex++);
        result &= chk.checkImage(image, testName);
    }

    // toggle mask visibility

    mask->setVisible(false);
    mask->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_mask_visible_off").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    mask->setVisible(true);
    mask->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_mask_visible_on").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    // entire bounds update

    // no clearing, just don't hang up

    paintLayer->setDirty(refRect);
    image->waitForDone();
    testName = QString("tm_%1_layer_dirty_bounds").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    // no clearing, just don't hang up

    mask->setDirty(refRect);
    image->waitForDone();
    testName = QString("tm_%1_mask_dirty_bounds").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    if (paintLayer != visibilityToggleLayer) {
        // no clearing, just don't hang up

        visibilityToggleLayer->setDirty(refRect);
        image->waitForDone();
        testName = QString("tm_%1_extra_layer_dirty_bounds").arg(testIndex++);
        result &= chk.checkImage(image, testName);
    }

    QRect fillRect;

    // partial updates outside

    fillRect = QRect(-100, 0.5 * refRect.height(), 50, 100);
    paintLayer->paintDevice()->fill(fillRect, KoColor(Qt::red, image->colorSpace()));
    paintLayer->setDirty(fillRect);
    image->waitForDone();
    testName = QString("tm_%1_layer_dirty_outside_%2_%3").arg(testIndex++).arg(fillRect.x()).arg(fillRect.y());
    result &= chk.checkImage(image, testName);

    fillRect = QRect(0.5 * refRect.width(), -100, 100, 50);
    paintLayer->paintDevice()->fill(fillRect, KoColor(Qt::red, image->colorSpace()));
    paintLayer->setDirty(fillRect);
    image->waitForDone();
    testName = QString("tm_%1_layer_dirty_outside_%2_%3").arg(testIndex++).arg(fillRect.x()).arg(fillRect.y());
    result &= chk.checkImage(image, testName);

    fillRect = QRect(refRect.width() + 50, 0.2 * refRect.height(), 50, 100);
    paintLayer->paintDevice()->fill(fillRect, KoColor(Qt::red, image->colorSpace()));
    paintLayer->setDirty(fillRect);
    image->waitForDone();
    testName = QString("tm_%1_layer_dirty_outside_%2_%3").arg(testIndex++).arg(fillRect.x()).arg(fillRect.y());
    result &= chk.checkImage(image, testName);

    // partial update inside

    fillRect = QRect(0.5 * refRect.width() - 50, 0.5 * refRect.height() - 50, 100, 100);
    paintLayer->paintDevice()->fill(fillRect, KoColor(Qt::red, image->colorSpace()));
    paintLayer->setDirty(fillRect);
    image->waitForDone();
    testName = QString("tm_%1_layer_dirty_inside_%2_%3").arg(testIndex++).arg(fillRect.x()).arg(fillRect.y());
    result &= chk.checkImage(image, testName);

    // clear explicitly
    image->projection()->clear();

    mask->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_mask_dirty_bounds").arg(testIndex++);
    result &= chk.checkImage(image, testName);


    KisDumbTransformMaskParams *params =
        dynamic_cast<KisDumbTransformMaskParams*>(mask->transformParams().data());

    QTransform t = params->testingGetTransform();
    t *= QTransform::fromTranslate(400, 300);
    params->testingSetTransform(t);
    mask->setTransformParams(mask->transformParams());

    mask->setDirty();
    image->waitForDone();
    testName = QString("tm_%1_mask_dirty_after_offset").arg(testIndex++);
    result &= chk.checkImage(image, testName);

    return result;
}
void KisAsyncMergerTest::testMerger()
{
    const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, 640, 441, colorSpace, "merger test");

    QImage sourceImage1(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png");
    QImage sourceImage2(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png");
    QImage referenceProjection(QString(FILES_DATA_DIR) + QDir::separator() + "merged_hakonepa.png");

    KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace);
    KisPaintDeviceSP device2 = new KisPaintDevice(colorSpace);
    device1->convertFromQImage(sourceImage1, 0, 0, 0);
    device2->convertFromQImage(sourceImage2, 0, 0, 0);

    KisFilterSP filter = KisFilterRegistry::instance()->value("blur");
    Q_ASSERT(filter);
    KisFilterConfiguration *configuration = filter->defaultConfiguration(0);
    Q_ASSERT(configuration);

    KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1);
    KisLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8, device2);
    KisLayerSP groupLayer = new KisGroupLayer(image, "group", 200/*OPACITY_OPAQUE*/);
    KisLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0);

    image->addNode(paintLayer1, image->rootLayer());
    image->addNode(groupLayer, image->rootLayer());

    image->addNode(paintLayer2, groupLayer);
    image->addNode(blur1, groupLayer);

    QRect testRect1(0,0,100,441);
    QRect testRect2(100,0,400,441);
    QRect testRect3(500,0,140,441);
    QRect testRect4(580,381,40,40);

    QRect cropRect(image->bounds());

    KisMergeWalker walker(cropRect);
    KisAsyncMerger merger;

    walker.collectRects(paintLayer2, testRect1);
    merger.startMerge(walker);

    walker.collectRects(paintLayer2, testRect2);
    merger.startMerge(walker);

    walker.collectRects(paintLayer2, testRect3);
    merger.startMerge(walker);

    walker.collectRects(paintLayer2, testRect4);
    merger.startMerge(walker);

    // Old style merging: has artefacts at x=100 and x=500
    // And should be turned on inside KisLayer
/*    paintLayer2->setDirty(testRect1);
    QTest::qSleep(3000);
    paintLayer2->setDirty(testRect2);
    QTest::qSleep(3000);
    paintLayer2->setDirty(testRect3);
    QTest::qSleep(3000);
    paintLayer2->setDirty(testRect4);
    QTest::qSleep(3000);
*/

    KisLayerSP rootLayer = image->rootLayer();
    QVERIFY(rootLayer->exactBounds() == image->bounds());

    QImage resultProjection = rootLayer->projection()->convertToQImage(0);
    resultProjection.save(QString(FILES_OUTPUT_DIR) + QDir::separator() + "actual_merge_result.png");
    QPoint pt;
    QVERIFY(TestUtil::compareQImages(pt, resultProjection, referenceProjection, 1));
}
void KisAsyncMergerTest::testFullRefreshWithClones()
{
    const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, 128, 128, colorSpace, "clones test");

    KisPaintDeviceSP device1 = new KisPaintDevice(colorSpace);
    device1->fill(image->bounds(), KoColor( Qt::white, colorSpace));

    KisFilterSP filter = KisFilterRegistry::instance()->value("invert");
    Q_ASSERT(filter);
    KisFilterConfiguration *configuration = filter->defaultConfiguration(0);
    Q_ASSERT(configuration);

    KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1);
    KisFilterMaskSP invertMask1 = new KisFilterMask();
    invertMask1->initSelection(0, paintLayer1);
    invertMask1->setFilter(configuration);

    KisLayerSP cloneLayer1 = new KisCloneLayer(paintLayer1, image, "clone_of_1", OPACITY_OPAQUE_U8);
    /**
     * The clone layer must have a projection to allow us
     * to read what it got from its source. Just shift it.
     */
    cloneLayer1->setX(10);
    cloneLayer1->setY(10);

    image->addNode(cloneLayer1, image->rootLayer());
    image->addNode(paintLayer1, image->rootLayer());
    image->addNode(invertMask1, paintLayer1);

    QRect cropRect(image->bounds());

    KisFullRefreshWalker walker(cropRect);
    KisAsyncMerger merger;

    walker.collectRects(image->rootLayer(), image->bounds());
    merger.startMerge(walker);

    // Wait for additional jobs generated by the clone are finished
    image->waitForDone();

    QRect filledRect(10, 10,
                     image->width() - cloneLayer1->x(),
                     image->height() - cloneLayer1->y());

    const int pixelSize = device1->pixelSize();
    const int numPixels = filledRect.width() * filledRect.height();

    QByteArray bytes(numPixels * pixelSize, 13);
    cloneLayer1->projection()->readBytes((quint8*)bytes.data(), filledRect);

    KoColor desiredPixel(Qt::black, colorSpace);
    quint8 *srcPtr = (quint8*)bytes.data();
    quint8 *dstPtr = desiredPixel.data();
    for(int i = 0; i < numPixels; i++) {
        if(memcmp(srcPtr, dstPtr, pixelSize)) {
            qDebug() << "expected:" << dstPtr[0] << dstPtr[1] << dstPtr[2] << dstPtr[3];
            qDebug() << "result:  " << srcPtr[0] << srcPtr[1] << srcPtr[2] << srcPtr[3];
            QFAIL("Failed to compare pixels");
        }
        srcPtr += pixelSize;
    }
}
 KUndo2Command* paint() {
     KisSelectionSP selection = m_image->globalSelection();
     KisSelectionTransaction transaction(selection->pixelSelection());
     selection->pixelSelection()->select(m_image->bounds());
     return transaction.endAndTake();
 }