Esempio n. 1
0
void KisImageTest::testLayerComposition()
{
    KisImageSP image = new KisImage(0, IMAGE_WIDTH, IMAGE_WIDTH, 0, "layer tests");
    QVERIFY(image->rootLayer() != 0);
    QVERIFY(image->rootLayer()->firstChild() == 0);

    KisLayerSP layer = new KisPaintLayer(image, "layer 1", OPACITY_OPAQUE_U8);
    image->addNode(layer);
    KisLayerSP layer2 = new KisPaintLayer(image, "layer 2", OPACITY_OPAQUE_U8);
    image->addNode(layer2);

    QVERIFY(layer->visible());
    QVERIFY(layer2->visible());

    KisLayerComposition comp(image, "comp 1");
    comp.store();

    layer2->setVisible(false);

    QVERIFY(layer->visible());
    QVERIFY(!layer2->visible());

    KisLayerComposition comp2(image, "comp 2");
    comp2.store();

    comp.apply();

    QVERIFY(layer->visible());
    QVERIFY(layer2->visible());

    comp2.apply();

    QVERIFY(layer->visible());
    QVERIFY(!layer2->visible());
}
Esempio n. 2
0
void KisImageTest::testMergeDownDestinationSameCompositeOp()
{
    FlattenTestImage p;

    TestUtil::ExternalImageChecker img("flatten", "imagetest");
    TestUtil::ExternalImageChecker chk("mergedown_sameop_fastpath", "imagetest");

    {
        QCOMPARE(p.layer8->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(p.layer8->alphaChannelDisabled(), false);

        QCOMPARE(p.layer7->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(p.layer7->alphaChannelDisabled(), false);

        KisLayerSP newLayer = p.image->mergeDown(p.layer8, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer8_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(newLayer->exactBounds(), QRect(50, 350, 50, 100));
        QCOMPARE(newLayer->alphaChannelDisabled(), false);
    }
}
Esempio n. 3
0
void testMergeCrossColorSpaceImpl(bool useProjectionColorSpace, bool swapSpaces)
{
    QRect refRect;
    TestUtil::MaskParent p;

    KisPaintLayerSP layer1;
    KisPaintLayerSP layer2;
    KisPaintLayerSP layer3;

    const KoColorSpace *cs2 = useProjectionColorSpace ?
        p.image->colorSpace() : KoColorSpaceRegistry::instance()->lab16();

    const KoColorSpace *cs3 = KoColorSpaceRegistry::instance()->rgb16();

    if (swapSpaces) {
        qSwap(cs2, cs3);
    }

    dbgKrita << "Testing testMergeCrossColorSpaceImpl:";
    dbgKrita << "    " << ppVar(cs2);
    dbgKrita << "    " << ppVar(cs3);

    layer1 = p.layer;
    layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8, cs2);
    layer3 = new KisPaintLayer(p.image, "paint3", OPACITY_OPAQUE_U8, cs3);

    QRect rect1(100, 100, 100, 100);
    QRect rect2(150, 150, 150, 150);
    QRect rect3(250, 250, 200, 200);

    layer1->paintDevice()->fill(rect1, KoColor(Qt::red, layer1->colorSpace()));
    layer2->paintDevice()->fill(rect2, KoColor(Qt::green, layer2->colorSpace()));
    layer3->paintDevice()->fill(rect3, KoColor(Qt::blue, layer3->colorSpace()));

    p.image->addNode(layer2);
    p.image->addNode(layer3);

    p.image->initialRefreshGraph();


    {
        KisLayerSP newLayer = p.image->mergeDown(layer3, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QCOMPARE(newLayer->colorSpace(), p.image->colorSpace());

        p.undoStore->undo();
    }

    {
        layer2->disableAlphaChannel(true);

        KisLayerSP newLayer = p.image->mergeDown(layer3, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QCOMPARE(newLayer->colorSpace(), p.image->colorSpace());

        p.undoStore->undo();
    }
}
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());
}
    bool addNewLayer(int row) {
        Q_UNUSED(row);

        if (nodeInterface) {
            KisLayerSP layer = nodeInterface->addPaintLayer();
            layer->setUseInTimeline(true);
        }

        return true;
    }
Esempio n. 6
0
void KisImageTest::layerTests()
{
    KisImageSP image = new KisImage(0, IMAGE_WIDTH, IMAGE_WIDTH, 0, "layer tests");
    QVERIFY(image->rootLayer() != 0);
    QVERIFY(image->rootLayer()->firstChild() == 0);

    KisLayerSP layer = new KisPaintLayer(image, "layer 1", OPACITY_OPAQUE_U8);
    image->addNode(layer);

    QVERIFY(image->rootLayer()->firstChild()->objectName() == layer->objectName());
}
Esempio n. 7
0
bool KisColorSpaceConvertVisitor::visit(KisGroupLayer * layer)
{
    convertPaintDevice(layer);
    KisLayerSP child = dynamic_cast<KisLayer*>(layer->firstChild().data());
    while (child) {
        child->accept(*this);
        child = dynamic_cast<KisLayer*>(child->nextSibling().data());
    }

    layer->resetCache();

    return true;
}
Esempio n. 8
0
void KisIndirectPaintingSupport::mergeToLayerImpl(KisLayerSP layer,
                                                  UndoAdapter *undoAdapter,
                                                  const KUndo2MagicString &transactionText)
{
    /**
     * We do not apply selection here, because it has already
     * been taken into account in a tool code
     */
    KisPainter gc(layer->paintDevice());
    setupTemporaryPainter(&gc);

    d->lock.lockForWrite();

    /**
     * Scratchpad may not have an undo adapter
     */
    if(undoAdapter) {
        gc.beginTransaction(transactionText);
    }
    foreach (const QRect &rc, d->temporaryTarget->region().rects()) {
        gc.bitBlt(rc.topLeft(), d->temporaryTarget, rc);
    }
    releaseResources();

    if(undoAdapter) {
        gc.endTransaction(undoAdapter);
    }

    d->lock.unlock();
}
Esempio n. 9
0
    KisNodeSP findNode(KisNodeSP node, const QPoint &point, bool wholeGroup, bool editableOnly)
    {
        KisNodeSP foundNode = 0;
        while (node) {
            KisLayerSP layer = dynamic_cast<KisLayer*>(node.data());

            if (!layer || !layer->isEditable()) {
                node = node->prevSibling();
                continue;
            }

            KoColor color(layer->projection()->colorSpace());
            layer->projection()->pixel(point.x(), point.y(), &color);

            KisGroupLayerSP group = dynamic_cast<KisGroupLayer*>(layer.data());

            if ((group && group->passThroughMode()) ||  color.opacityU8() != OPACITY_TRANSPARENT_U8) {
                if (layer->inherits("KisGroupLayer") && (!editableOnly || layer->isEditable())) {
                    // if this is a group and the pixel is transparent, don't even enter it
                    foundNode = findNode(node->lastChild(), point, wholeGroup, editableOnly);
                }
                else {
                    foundNode = !wholeGroup ? node : node->parent();
                }

            }

            if (foundNode) break;

            node = node->prevSibling();
        }

        return foundNode;
    }
Esempio n. 10
0
void KisRecordedFilterAction::play(KisNodeSP node, const KisPlayInfo& _info, KoUpdater* _updater) const
{
    KisFilterConfiguration * kfc = d->configuration();
    KisPaintDeviceSP dev = node->paintDevice();
    KisLayerSP layer = dynamic_cast<KisLayer*>(node.data());
    QRect r1 = dev->extent();
    KisTransaction transaction(kundo2_i18n("Filter: \"%1\"", d->filter->name()), dev);

    KisImageWSP image = _info.image();
    r1 = r1.intersected(image->bounds());
    if (layer && layer->selection()) {
        r1 = r1.intersected(layer->selection()->selectedExactRect());
    }

    d->filter->process(dev, dev, layer->selection(), r1, kfc, _updater);
    node->setDirty(r1);

    transaction.commit(_info.undoAdapter());
}
Esempio n. 11
0
KisSelectionSP KisResourcesSnapshot::activeSelection() const
{
    /**
     * It is possible to have/use the snapshot without the image. Such
     * usecase is present for example in the scratchpad.
     */
    KisSelectionSP selection = m_d->image ? m_d->image->globalSelection() : 0;

    KisLayerSP layer = dynamic_cast<KisLayer*>(m_d->currentNode.data());
    KisSelectionMaskSP mask;
    if((layer = dynamic_cast<KisLayer*>(m_d->currentNode.data()))) {
        selection = layer->selection();
    } else if ((mask = dynamic_cast<KisSelectionMask*>(m_d->currentNode.data())) &&
               mask->selection() == selection) {

        selection = 0;
    }

    return selection;
}
void KisIndirectPaintingSupport::mergeToLayer(KisLayerSP layer, const QRegion &region, const QString &transactionText)
{
    /**
     * We do not apply selection here, because it has already
     * been taken into account in a tool code
     */
    KisPainter gc(layer->paintDevice());
    gc.setCompositeOp(d->compositeOp);
    gc.setOpacity(d->compositeOpacity);
    gc.setChannelFlags(layer->channelFlags());

    if (KisPaintLayer* paintLayer = dynamic_cast<KisPaintLayer*>(layer.data())) {
        if (paintLayer->alphaLocked()) {
            gc.setLockAlpha(paintLayer->alphaLocked());
        }
    }

    d->lock.lockForWrite();
    if(layer->image()) {
        gc.beginTransaction(transactionText);
    }

    foreach(const QRect& rc, region.rects()) {
        gc.bitBlt(rc.topLeft(), d->temporaryTarget, rc);
    }
    d->temporaryTarget = 0;

    // in the scratchpad the layer has no image and there is no undo adapter
    if(layer->image()) {
        gc.endTransaction(layer->image()->undoAdapter());
    }

    d->lock.unlock();
}
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());
}
Esempio n. 14
0
KoShapeManager* KisCanvas2::shapeManager() const
{
    if (!m_d->view) return m_d->shapeManager;
    if (!m_d->view->layerManager()) return m_d->shapeManager;

    KisLayerSP activeLayer = m_d->view->layerManager()->activeLayer();
    if (activeLayer) {
        KisShapeLayer * shapeLayer = dynamic_cast<KisShapeLayer*>(activeLayer.data());
        if (shapeLayer) {
            dbgUI << "Current shape manager belongs to a shape layer " << shapeLayer->shapeManager();
            return shapeLayer->shapeManager();
        }
        if (activeLayer->selection() && activeLayer->selection()->hasShapeSelection()) {
            KoShapeManager* m = static_cast<KisShapeSelection*>(activeLayer->selection()->shapeSelection())->shapeManager();
            dbgUI << "Current shape manager belongs to a shape selection " << m;
            return m;

        }
    }
    dbgUI << "current shape manager belongs to the main canvas " << m_d->shapeManager;

    return m_d->shapeManager;
}
Esempio n. 15
0
void KisLayerTest::testHasEffectMasks()
{
    KisLayerSP layer = new TestLayer(0, "layer1", OPACITY_OPAQUE) ;
    QVERIFY(layer->hasEffectMasks() == false);
    KisFilterMaskSP mask = new KisFilterMask();
    layer->setPreviewMask(mask);
    QVERIFY(layer->hasEffectMasks());
    layer->removePreviewMask();
    QVERIFY(layer->hasEffectMasks() == false);
}
Esempio n. 16
0
/**
 * This benchmark runs a series of huge strokes on a canvas with a
 * particular configuration of the swapper/pooler and history
 * management. After the test is done you can visualize the results
 * with the GNU Octave. Please use kis_low_memory_show_report.m file
 * for that.
 */
void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName,
                                              const QRectF &rect, qreal vstep,
                                              int numCycles,
                                              bool createTransaction,
                                              int hardLimitMiB,
                                              int softLimitMiB,
                                              int poolLimitMiB,
                                              int index)
{
    KisPaintOpPresetSP preset = new KisPaintOpPreset(QString(FILES_DATA_DIR) + QDir::separator() + presetFileName);
    LOAD_PRESET_OR_RETURN(preset, presetFileName);


    /**
     * Initialize image and painter
     */
    const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
    KisImageSP image = new KisImage(0, HUGE_IMAGE_SIZE, HUGE_IMAGE_SIZE, colorSpace, "stroke sample image", true);
    KisLayerSP layer = new KisPaintLayer(image, "temporary for stroke sample", OPACITY_OPAQUE_U8, colorSpace);
    KisLayerSP layerExtra = new KisPaintLayer(image, "temporary for threading", OPACITY_OPAQUE_U8, colorSpace);

    image->addNode(layer, image->root());
    image->addNode(layerExtra, image->root());

    KisPainter *painter = new KisPainter(layer->paintDevice());

    painter->setPaintColor(KoColor(Qt::black, colorSpace));
    painter->setPaintOpPreset(preset, layer, image);

    /**
     * A simple adapter that will store all the transactions for us
     */
    KisSurrogateUndoAdapter undoAdapter;

    /**
     * Reset configuration to the desired settings
     */
    KisImageConfig config;
    qreal oldHardLimit = config.memoryHardLimitPercent();
    qreal oldSoftLimit = config.memorySoftLimitPercent();
    qreal oldPoolLimit = config.memoryPoolLimitPercent();
    const qreal _MiB = 100.0 / KisImageConfig::totalRAM();

    config.setMemoryHardLimitPercent(hardLimitMiB * _MiB);
    config.setMemorySoftLimitPercent(softLimitMiB * _MiB);
    config.setMemoryPoolLimitPercent(poolLimitMiB * _MiB);

    KisTileDataStore::instance()->testingRereadConfig();

    /**
     * Create an empty the log file
     */
    QString fileName;
    fileName = QString("log_%1_%2_%3_%4_%5.txt")
        .arg(createTransaction)
        .arg(hardLimitMiB)
        .arg(softLimitMiB)
        .arg(poolLimitMiB)
        .arg(index);

    QFile logFile(fileName);
    logFile.open(QFile::WriteOnly | QFile::Truncate);
    QTextStream logStream(&logFile);
    logStream.setFieldWidth(10);
    logStream.setFieldAlignment(QTextStream::AlignRight);

    /**
     * Start painting on the image
     */

    QTime cycleTime;
    QTime lineTime;
    cycleTime.start();
    lineTime.start();

    qreal rectBottom = rect.y() + rect.height();

    for (int i = 0; i < numCycles; i++) {
        cycleTime.restart();

        QLineF line(rect.topLeft(), rect.topLeft() + QPointF(rect.width(), 0));
        if (createTransaction) {
            painter->beginTransaction();
        }

        KisDistanceInformation currentDistance;

        while(line.y1() < rectBottom) {
            lineTime.restart();

            KisPaintInformation pi1(line.p1(), 0.0);
            KisPaintInformation pi2(line.p2(), 1.0);
            painter->paintLine(pi1, pi2, &currentDistance);
            painter->device()->setDirty(painter->takeDirtyRegion());

            logStream << "L 1" << i << lineTime.elapsed()
                      << KisTileDataStore::instance()->numTilesInMemory() * 16
                      << KisTileDataStore::instance()->numTiles() * 16
                      << createTransaction << endl;

            line.translate(0, vstep);
        }

        painter->device()->setDirty(painter->takeDirtyRegion());

        if (createTransaction) {
            painter->endTransaction(&undoAdapter);
        }

        // comment/uncomment to emulate user waiting after the stroke
        QTest::qSleep(1000);

        logStream << "C 2" << i << cycleTime.elapsed()
                  << KisTileDataStore::instance()->numTilesInMemory() * 16
                  << KisTileDataStore::instance()->numTiles() * 16
                  << createTransaction
                  << config.memoryHardLimitPercent() / _MiB
                  << config.memorySoftLimitPercent() / _MiB
                  << config.memoryPoolLimitPercent() / _MiB  << endl;
    }

    config.setMemoryHardLimitPercent(oldHardLimit * _MiB);
    config.setMemorySoftLimitPercent(oldSoftLimit * _MiB);
    config.setMemoryPoolLimitPercent(oldPoolLimit * _MiB);

    delete painter;
}
Esempio n. 17
0
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;
}
Esempio n. 18
0
void KisRecordedPaintAction::play(KisNodeSP node, const KisPlayInfo& info) const
{
    dbgUI << "Play recorded paint action on node : " << node->name() ;
    KisTransaction * cmd = 0;
    if (info.undoAdapter()) cmd = new KisTransaction("", node->paintDevice());

    KisPaintDeviceSP target = 0;
    if (d->paintIncremental) {
        target = node->paintDevice();
    } else {
        target = new KisPaintDevice(node->paintDevice()->colorSpace());
    }

    KisPainter painter(target);

    KisImageSP image;
    KisNodeSP parent = node;
    while (image == 0 && parent->parent()) {
        // XXX: ugly!
        KisLayerSP layer = dynamic_cast<KisLayer*>(parent.data());
        if (layer) {
            image = layer->image();
        }
        parent = parent->parent();
    }

    painter.setPaintOpPreset(d->paintOpPreset, image);

    if (d->paintIncremental) {
        painter.setCompositeOp(d->compositeOp);
        painter.setOpacity(d->opacity);
    } else {
        painter.setCompositeOp(node->paintDevice()->colorSpace()->compositeOp(COMPOSITE_ALPHA_DARKEN));
        painter.setOpacity(OPACITY_OPAQUE);

    }

    painter.setPaintColor(d->foregroundColor);
    painter.setFillColor(d->backgroundColor);

    playPaint(info, &painter);

    if (!d->paintIncremental) {
        KisPainter painter2(node->paintDevice());
        painter2.setCompositeOp(d->compositeOp);
        painter2.setOpacity(d->opacity);
        
        QRegion r = painter.dirtyRegion();
        QVector<QRect> dirtyRects = r.rects();
        QVector<QRect>::iterator it = dirtyRects.begin();
        QVector<QRect>::iterator end = dirtyRects.end();
        while (it != end) {
            painter2.bitBlt(it->topLeft(), target, *it);
            ++it;
        }

        node->setDirty(painter2.dirtyRegion());
    } else {
        node->setDirty(painter.dirtyRegion());
    }
    if (info.undoAdapter()) info.undoAdapter()->addCommand(cmd);
}
Esempio n. 19
0
void KisLayerTest::testCreation()
{

    const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->colorSpace("RGBA", 0);
    KisImageSP image = new KisImage(0, 512, 512, colorSpace, "layer test");

    KisLayerSP layer = new TestLayer(image, "test", OPACITY_OPAQUE);
    QCOMPARE(layer->name(), QString("test"));
    QCOMPARE(layer->opacity(), OPACITY_OPAQUE);
    QCOMPARE(layer->image(), image);
    QCOMPARE(layer->colorSpace(), image->colorSpace());
    QCOMPARE(layer->visible(), true);
    QCOMPARE(layer->userLocked(), false);
    QCOMPARE(layer->temporary(), false);

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

    QBitArray channels(4);
    channels.fill(true);
    layer->setChannelFlags(channels);
    QVERIFY(layer->channelFlags().count() == 4);
    QCOMPARE(layer->channelFlags().at(0), true);
    QCOMPARE(layer->channelFlags().at(1), true);
    QCOMPARE(layer->channelFlags().at(2), true);
    QCOMPARE(layer->channelFlags().at(3), true);


    layer->setOpacity(OPACITY_TRANSPARENT);
    QCOMPARE(layer->opacity(), OPACITY_TRANSPARENT);
    layer->setPercentOpacity(100);
    QCOMPARE(layer->opacity(), OPACITY_OPAQUE);
    layer->setPercentOpacity(0);
    QCOMPARE(layer->opacity(), OPACITY_TRANSPARENT);


}
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));
}
Esempio n. 21
0
KisImportExportFilter::ConversionStatus KisXCFImport::loadFromDevice(QIODevice* device, KisDocument* doc)
{
    dbgFile << "Start decoding file";
    // Read the file into memory
    device->open(QIODevice::ReadOnly);
    QByteArray data = device->readAll();
    xcf_file = (uint8_t*)data.data();
    xcf_length = data.size();
    device->close();

    // Decode the data
    getBasicXcfInfo() ;
    initColormap();

    dbgFile << XCF.version << "width = " << XCF.width << "height = " << XCF.height << "layers = " << XCF.numLayers;

    // Create the image
    KisImageSP image = new KisImage(doc->createUndoStore(), XCF.width, XCF.height, KoColorSpaceRegistry::instance()->rgb8(), "built image");

    QVector<Layer> layers;
    uint maxDepth = 0;

    // Read layers
    for (int i = 0; i < XCF.numLayers; ++i) {

        Layer layer;

        xcfLayer& xcflayer = XCF.layers[i];
        dbgFile << i << " name = " << xcflayer.name << " opacity = " << xcflayer.opacity << "group:" << xcflayer.isGroup << xcflayer.pathLength;
        dbgFile << ppVar(xcflayer.dim.width) << ppVar(xcflayer.dim.height) << ppVar(xcflayer.dim.tilesx) << ppVar(xcflayer.dim.tilesy) << ppVar(xcflayer.dim.ntiles) << ppVar(xcflayer.dim.c.t) << ppVar(xcflayer.dim.c.l) << ppVar(xcflayer.dim.c.r) << ppVar(xcflayer.dim.c.b);

        maxDepth = qMax(maxDepth, xcflayer.pathLength);

        bool isRgbA = false;
        // Select the color space
        const KoColorSpace* colorSpace = 0;
        switch (xcflayer.type) {
        case GIMP_INDEXED_IMAGE:
        case GIMP_INDEXEDA_IMAGE:
        case GIMP_RGB_IMAGE:
        case GIMP_RGBA_IMAGE:
            colorSpace = KoColorSpaceRegistry::instance()->rgb8();
            isRgbA = true;
            break;
        case GIMP_GRAY_IMAGE:
        case GIMP_GRAYA_IMAGE:
            colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "");
            isRgbA = false;
            break;
        }

        // Create the layer
        KisLayerSP kisLayer;
        if (xcflayer.isGroup) {
            kisLayer = new KisGroupLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity);
        }
        else {
            kisLayer = new KisPaintLayer(image, QString::fromUtf8(xcflayer.name), xcflayer.opacity, colorSpace);
        }

        // Set some properties
        kisLayer->setCompositeOpId(layerModeG2K(xcflayer.mode));
        kisLayer->setVisible(xcflayer.isVisible);
        kisLayer->disableAlphaChannel(xcflayer.mode != GIMP_NORMAL_MODE);

        layer.layer = kisLayer;
        layer.depth = xcflayer.pathLength;

        // Copy the data in the image
        initLayer(&xcflayer);

        int left = xcflayer.dim.c.l;
        int top = xcflayer.dim.c.t;

        if (!xcflayer.isGroup) {

            // Copy the data;
            for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) {
                for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) {
                    rect want;
                    want.l = x + left;
                    want.t = y + top;
                    want.b = want.t + TILE_HEIGHT;
                    want.r = want.l + TILE_WIDTH;
                    Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.pixels, want);
                    KisHLineIteratorSP it = kisLayer->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH);
                    rgba* data = tile->pixels;
                    for (int v = 0; v < TILE_HEIGHT; ++v) {
                        if (isRgbA) {
                            // RGB image
                           do {
                                KoBgrTraits<quint8>::setRed(it->rawData(), GET_RED(*data));
                                KoBgrTraits<quint8>::setGreen(it->rawData(), GET_GREEN(*data));
                                KoBgrTraits<quint8>::setBlue(it->rawData(), GET_BLUE(*data));
                                KoBgrTraits<quint8>::setOpacity(it->rawData(), quint8(GET_ALPHA(*data)), 1);
                                ++data;
                            } while (it->nextPixel());
                        } else {
                            // Grayscale image
                            do {
                                it->rawData()[0] = GET_RED(*data);
                                it->rawData()[1] = GET_ALPHA(*data);
                                ++data;
                            } while (it->nextPixel());
                        }
                        it->nextRow();
                    }
                }
            }

            // Move the layer to its position
            kisLayer->paintDevice()->setX(left);
            kisLayer->paintDevice()->setY(top);
        }
        // Create the mask
        if (xcflayer.hasMask) {
            KisTransparencyMaskSP mask = new KisTransparencyMask();
            layer.mask = mask;

            mask->initSelection(kisLayer);
            for (unsigned int x = 0; x < xcflayer.dim.width; x += TILE_WIDTH) {
                for (unsigned int y = 0; y < xcflayer.dim.height; y += TILE_HEIGHT) {
                    rect want;
                    want.l = x + left;
                    want.t = y + top;
                    want.b = want.t + TILE_HEIGHT;
                    want.r = want.l + TILE_WIDTH;
                    Tile* tile = getMaskOrLayerTile(&xcflayer.dim, &xcflayer.mask, want);
                    KisHLineIteratorSP it = mask->paintDevice()->createHLineIteratorNG(x, y, TILE_WIDTH);
                    rgba* data = tile->pixels;
                    for (int v = 0; v < TILE_HEIGHT; ++v) {
                        do {
                            it->rawData()[0] = GET_ALPHA(*data);
                            ++data;
                        } while (it->nextPixel());
                        it->nextRow();
                    }

                }
            }
            mask->paintDevice()->setX(left);
            mask->paintDevice()->setY(top);
            image->addNode(mask, kisLayer);
        }

        dbgFile << xcflayer.pixels.tileptrs;
        layers.append(layer);
    }

    for (int i = 0; i <= maxDepth; ++i) {
        addLayers(layers, image, i);
    }

    doc->setCurrentImage(image);
    return KisImportExportFilter::OK;
}
Esempio n. 22
0
void KisImageTest::testFlattenLayer()
{
    FlattenTestImage p;

    TestUtil::ExternalImageChecker chk("flatten", "imagetest");

    {
        QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD);

        KisLayerSP newLayer = p.image->flattenLayer(p.layer2);
        p.image->waitForDone();

        QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer2_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER);
    }

    {
        QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD);

        KisLayerSP newLayer = p.image->flattenLayer(p.group1);
        p.image->waitForDone();

        QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "02_group1_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(newLayer->exactBounds(), QRect(400, 100, 200, 100));
    }

    {
        QCOMPARE(p.layer5->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(p.layer5->alphaChannelDisabled(), true);

        KisLayerSP newLayer = p.image->flattenLayer(p.layer5);
        p.image->waitForDone();

        QVERIFY(chk.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "03_layer5_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(newLayer->exactBounds(), QRect(50, 50, 100, 100));

        QCOMPARE(newLayer->alphaChannelDisabled(), true);
    }
}
Esempio n. 23
0
void KisImageTest::testMergeDown()
{
    FlattenTestImage p;

    TestUtil::ExternalImageChecker img("flatten", "imagetest");
    TestUtil::ExternalImageChecker chk("mergedown_simple", "imagetest");


    {
        QCOMPARE(p.layer5->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(p.layer5->alphaChannelDisabled(), true);

        KisLayerSP newLayer = p.image->mergeDown(p.layer5, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "01_layer5_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(newLayer->alphaChannelDisabled(), false);
    }

    {
        QCOMPARE(p.layer2->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(p.layer2->alphaChannelDisabled(), false);

        KisLayerSP newLayer = p.image->mergeDown(p.layer2, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "02_layer2_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(newLayer->exactBounds(), QRect(100, 100, 213, 217));
        QCOMPARE(newLayer->alphaChannelDisabled(), false);
    }

    {
        QCOMPARE(p.group1->compositeOpId(), COMPOSITE_ADD);
        QCOMPARE(p.group1->alphaChannelDisabled(), false);

        KisLayerSP newLayer = p.image->mergeDown(p.group1, KisMetaData::MergeStrategyRegistry::instance()->get("Drop"));
        p.image->waitForDone();

        QVERIFY(img.checkDevice(p.image->projection(), p.image, "00_initial"));
        QVERIFY(chk.checkDevice(newLayer->projection(), p.image, "03_group1_mergedown_layerproj"));

        QCOMPARE(newLayer->compositeOpId(), COMPOSITE_OVER);
        QCOMPARE(newLayer->exactBounds(), QRect(100, 100, 500, 217));
        QCOMPARE(newLayer->alphaChannelDisabled(), false);
    }
}