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()); }
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); } }
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; }
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()); }
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; }
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(); }
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; }
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()); }
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 ®ion, 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()); }
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; }
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); }
/** * 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, ¤tDistance); 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; }
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 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); }
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)); }
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; }
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); } }
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); } }