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; }
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(); }