QRect KisFilterMask::decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect & rc, PositionToFilthy maskPos) const { Q_UNUSED(maskPos); KisSafeFilterConfigurationSP filterConfig = filter(); Q_ASSERT(nodeProgressProxy()); Q_ASSERT_X(src != dst, "KisFilterMask::decorateRect", "src must be != dst, because we cant create transactions " "during merge, as it breaks reentrancy"); if (!filterConfig) { return QRect(); } KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); if (!filter) { warnKrita << "Could not retrieve filter \"" << filterConfig->name() << "\""; return QRect(); } KIS_ASSERT_RECOVER_NOOP(this->busyProgressIndicator()); this->busyProgressIndicator()->update(); filter->process(src, dst, 0, rc, filterConfig.data(), 0); QRect r = filter->changedRect(rc, filterConfig.data(), dst->defaultBounds()->currentLevelOfDetail()); return r; }
void KisBContrastBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("brightnesscontrast"); KisFilterConfigurationSP kfc = filter->defaultConfiguration(m_device); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } QSize size = KritaUtils::optimalPatchSize(); QVector<QRect> rects = KritaUtils::splitRectIntoPatches(QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), size); QBENCHMARK{ Q_FOREACH (const QRect &rc, rects) { filter->process(m_device, rc, kfc); } }
void KisFilterTest::testDifferentSrcAndDst() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisPaintDeviceSP src = new KisPaintDevice(cs); KisPaintDeviceSP dst = new KisPaintDevice(cs); KisSelectionSP sel = new KisSelection(new KisSelectionDefaultBounds(src)); sel->getOrCreatePixelSelection()->invert(); // select everything sel->updateProjection(); src->convertFromQImage(qimage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); KisFilterConfiguration * kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(src, dst, sel, QRect(QPoint(0,0), qimage.size()), kfc); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, dst->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dst->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtertest.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } }
KisNodeSP KisKraLoader::loadAdjustmentLayer(const KoXmlElement& element, KisImageWSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { // XXX: do something with filterversion? Q_UNUSED(cs); QString attr; KisAdjustmentLayer* layer; QString filtername; if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid adjustmentlayer! We should warn about it! warnFile << "No filter in adjustment layer"; return 0; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } KisFilterConfiguration * kfc = f->defaultConfiguration(0); // We'll load the configuration and the selection later. layer = new KisAdjustmentLayer(image, name, kfc, 0); Q_CHECK_PTR(layer); layer->setOpacity(opacity); return layer; }
QRect KisFilterMask::needRect(const QRect& rect, PositionToFilthy pos) const { Q_UNUSED(pos); /** * FIXME: This check of the emptiness should be done * on the higher/lower level */ if(rect.isEmpty()) return rect; KisSafeFilterConfigurationSP filterConfig = filter(); if (!filterConfig) return rect; KisNodeSP parent = this->parent(); const int lod = parent && parent->projection() ? parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); /** * If we need some additional pixels even outside of a selection * for accurate layer filtering, we'll get them! * And no KisMask::needRect will prevent us from doing this! ;) * That's why simply we do not call KisMask::needRect here :) */ return filter->neededRect(rect, filterConfig.data(), lod); }
bool applyFilter(const KoColorSpace * cs, KisFilterSP f) { QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "lena.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); // dev->fill(0, 0, 100, 100, dev->defaultPixel()); dev->convertFromQImage(qimage, "", 0, 0); // Get the predefined configuration from a file KisFilterConfiguration * kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out << kfc->toXML(); } else { QString s; QTextStream in(&file); s = in.readAll(); kfc->fromXML(s); } qDebug() << f->id() << ", " << cs->id() << ", " << cs->profile()->name();// << kfc->toXML() << "\n"; KisConstProcessingInformation src(dev, QPoint(0, 0), 0); KisProcessingInformation dst(dev, QPoint(0, 0), 0); f->process(src, dst, qimage.size(), kfc); return true; }
KisNodeSP KisKraLoader::loadFilterMask(const KoXmlElement& element, KisNodeSP parent) { Q_UNUSED(parent); QString attr; KisFilterMask* mask; QString filtername; // XXX: should we check the version? if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid filter layer! We should warn about it! warnFile << "No filter in filter layer"; return 0; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } KisFilterConfiguration * kfc = f->defaultConfiguration(0); // We'll load the configuration and the selection later. mask = new KisFilterMask(); mask->setFilter(kfc); Q_CHECK_PTR(mask); return mask; }
/** * FIXME: try to cache filter pointer inside a Private block */ QRect KisFilterMask::changeRect(const QRect &rect, PositionToFilthy pos) const { /** * FIXME: This check of the emptiness should be done * on the higher/lower level */ if(rect.isEmpty()) return rect; QRect filteredRect = rect; KisSafeFilterConfigurationSP filterConfig = filter(); if (filterConfig) { KisNodeSP parent = this->parent(); const int lod = parent && parent->projection() ? parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); filteredRect = filter->changedRect(rect, filterConfig.data(), lod); } /** * We can't paint outside a selection, that is why we call * KisMask::changeRect to crop actual change area in the end */ filteredRect = KisMask::changeRect(filteredRect, pos); /** * FIXME: Think over this solution * Union of rects means that changeRect returns NOT the rect * changed by this very layer, but an accumulated rect changed * by all underlying layers. Just take into account and change * documentation accordingly */ return rect | filteredRect; }
void KisDlgFilter::filterSelectionChanged() { KisFilterSP filter = d->uiFilterDialog.filterSelection->currentFilter(); setDialogTitle(filter); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(filter.isNull() ? false : filter->supportsAdjustmentLayers()); updatePreview(); }
bool KisCrashFilterTest::applyFilter(const KoColorSpace * cs, KisFilterSP f) { QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "carrot.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); // dev->fill(0, 0, 100, 100, dev->defaultPixel()); dev->convertFromQImage(qimage, 0, 0, 0); // Get the predefined configuration from a file KisFilterConfigurationSP kfc = f->defaultConfiguration(dev); QFile file(QString(FILES_DATA_DIR) + QDir::separator() + f->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { dbgKrita << "creating new file for " << f->id(); file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } dbgKrita << f->id() << ", " << cs->id() << ", " << cs->profile()->name();// << kfc->toXML() << "\n"; f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc); return true; }
void KisFilterTest::testWithProgressUpdater() { TestUtil::TestProgressBar * bar = new TestUtil::TestProgressBar(); KoProgressUpdater* pu = new KoProgressUpdater(bar); KoUpdaterPtr updater = pu->startSubtask(); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->convertFromQImage(qimage, 0, 0, 0); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); KisFilterConfiguration * kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(dev, QRect(QPoint(0,0), qimage.size()), kfc, updater); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { dev->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtertest.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } delete pu; delete bar; }
KisFilterOption::KisFilterOption() : KisPaintOpOption(KisPaintOpOption::FILTER, true) { setObjectName("KisFilterOption"); m_checkable = false; m_filterOptionWidget = new KisFilterOptionWidget(); m_filterOptionWidget->hide(); setConfigurationPage(m_filterOptionWidget); m_layout = new QGridLayout(m_filterOptionWidget->grpFilterOptions); // Check which filters support painting QList<QString> l = KisFilterRegistry::instance()->keys(); QList<KoID> l2; QList<QString>::iterator it; for (it = l.begin(); it != l.end(); ++it) { KisFilterSP f = KisFilterRegistry::instance()->value((*it)); if (f->supportsPainting()) { l2.push_back(KoID(*it, f->name())); } } m_filterOptionWidget->filtersList->setIDList(l2); connect(m_filterOptionWidget->filtersList, SIGNAL(activated(const KoID &)), SLOT(setCurrentFilter(const KoID &))); if (!l2.empty()) { setCurrentFilter(l2.first()); } connect(m_filterOptionWidget->checkBoxSmudgeMode, SIGNAL(stateChanged(int)), this, SLOT(emitSettingChanged())); }
void KisLevelFilterBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("levels"); //KisFilterConfigurationSP kfc = filter->defaultConfiguration(m_device); KisColorTransformationConfiguration * kfc= new KisColorTransformationConfiguration("levels", 1); kfc->setProperty("blackvalue", 75); kfc->setProperty("whitevalue", 231); kfc->setProperty("gammavalue", 1.0); kfc->setProperty("outblackvalue", 0); kfc->setProperty("outwhitevalue", 255); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out.setCodec("UTF-8"); out << kfc->toXML(); } else { QString s; QTextStream in(&file); in.setCodec("UTF-8"); s = in.readAll(); kfc->fromXML(s); } QSize size = KritaUtils::optimalPatchSize(); QVector<QRect> rects = KritaUtils::splitRectIntoPatches(QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), size); QBENCHMARK{ Q_FOREACH (const QRect &rc, rects) { filter->process(m_device, rc, kfc); } }
void KisFilterMaskTest::testProjectionSelected() { KisImageSP image; KisPaintLayerSP layer; const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); QImage qimage(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); QImage inverted(QString(FILES_DATA_DIR) + QDir::separator() + "inverted_hakonepa.png"); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); KisFilterConfiguration * kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); KisFilterMaskSP mask = new KisFilterMask(); mask->setFilter(kfc); mask->createNodeProgressProxy(); KisPaintDeviceSP projection = new KisPaintDevice(cs); initImage(image, layer, projection, mask); projection->convertFromQImage(qimage, 0, 0, 0); mask->initSelection(layer); mask->select(qimage.rect(), MAX_SELECTED); mask->apply(projection, qimage.rect(), qimage.rect(), KisNode::N_FILTHY); QCOMPARE(mask->exactBounds(), QRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT)); QPoint errpoint; if (!TestUtil::compareQImages(errpoint, inverted, projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()))) { projection->convertToQImage(0, 0, 0, qimage.width(), qimage.height()).save("filtermasktest2.png"); QFAIL(QString("Failed to create inverted image, first different pixel: %1,%2 ").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } }
void KisSimpleUpdateQueueTest::testChecksum() { QRect imageRect(0,0,512,512); QRect dirtyRect(100,100,100,100); const KoColorSpace * colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), colorSpace, "test"); KisLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisAdjustmentLayerSP adjustmentLayer = new KisAdjustmentLayer(image, "adj", 0, 0); image->lock(); image->addNode(paintLayer1, image->rootLayer()); image->addNode(adjustmentLayer, image->rootLayer()); image->unlock(); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); KisFilterConfiguration *configuration = filter->defaultConfiguration(0); KisTestableSimpleUpdateQueue queue; KisWalkersList& walkersList = queue.getWalkersList(); { TestUtil::LodOverride l(1, image); queue.addUpdateJob(adjustmentLayer, dirtyRect, imageRect, 1); QCOMPARE(walkersList[0]->checksumValid(), true); QCOMPARE(walkersList[0]->levelOfDetail(), 1); } adjustmentLayer->setFilter(configuration); { TestUtil::LodOverride l(1, image); QCOMPARE(walkersList[0]->checksumValid(), false); } QVector<KisUpdateJobItem*> jobs; KisTestableUpdaterContext context(2); { TestUtil::LodOverride l(1, image); queue.processQueue(context); } jobs = context.getJobs(); { TestUtil::LodOverride l(1, image); QCOMPARE(jobs[0]->walker()->checksumValid(), true); } }
void KisFilterTest::testOldDataApiAfterCopy() { QRect updateRect(0,0,63,63); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); quint8 *whitePixel = new quint8[cs->pixelSize()]; cs->fromQColor(Qt::white, whitePixel); cs->setOpacity(whitePixel, OPACITY_OPAQUE_U8, 1); KisPaintDeviceSP tmp = new KisPaintDevice(cs); KisPaintDeviceSP src = new KisPaintDevice(cs); src->fill(0, 0, 50, 50, whitePixel); /** * Make a full copy here to catch the bug. * Buggy memento manager would make a commit * that is not good. */ KisPaintDeviceSP dst = new KisPaintDevice(*src); /** * This would write go to a new revision in a buggy * memento manager */ dst->clear(updateRect); KisFilterSP f = KisFilterRegistry::instance()->value("invert"); Q_ASSERT(f); KisFilterConfiguration * kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); /** * This filter reads from oldRawData, so if we have some * weirdness with transactions it will read from old and non-cleared * version of the device and we will see a black square instead * of empty device in tmp */ f->process(dst, tmp, 0, updateRect, kfc); /** * In theory, both devices: dst and tmp must be empty by now */ KisPaintDeviceSP reference = new KisPaintDevice(cs); QImage refImage = reference->convertToQImage(0,0,0,63,63); QImage dstImage = dst->convertToQImage(0,0,0,63,63); QImage tmpImage = tmp->convertToQImage(0,0,0,63,63); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, refImage, dstImage)); QVERIFY(TestUtil::compareQImages(pt, refImage, tmpImage)); }
KisFilterConfiguration* KisFilterOpSettings::filterConfig() const { if (hasProperty(FILTER_ID)) { KisFilterSP filter = KisFilterRegistry::instance()->get(getString(FILTER_ID)); if (filter) { KisFilterConfiguration* configuration = filter->factoryConfiguration(0); configuration->fromXML(getString(FILTER_CONFIGURATION)); return configuration; } } return 0; }
KisStrokeStrategy* createStroke(bool indirectPainting, KisResourcesSnapshotSP resources, KisImageWSP image) { Q_UNUSED(image); Q_UNUSED(indirectPainting); KisFilterSP filter = KisFilterRegistry::instance()->value(m_filterName); Q_ASSERT(filter); KisFilterConfiguration *filterConfig = filter->defaultConfiguration(0); Q_ASSERT(filterConfig); return new KisFilterStrokeStrategy(filter, KisSafeFilterConfigurationSP(filterConfig), resources); }
void KisFilterOpSettings::fromXML(const QDomElement& e) { KisPaintOpSettings::fromXML(e); QDomElement element = e.firstChildElement("filterconfig"); if (hasProperty(FILTER_ID)) { KisFilterSP filter = KisFilterRegistry::instance()->get(getString(FILTER_ID)); if (filter) { KisFilterConfiguration* configuration = filter->factoryConfiguration(0); configuration->fromXML(element); setProperty(FILTER_CONFIGURATION, configuration->toXML()); delete configuration; } } }
void KisFilterDialog::setFilter(KisFilterSP f) { Q_ASSERT(f); setWindowTitle(f->name()); d->currentFilter = f; d->uiFilterDialog.filterSelection->setFilter(f); updatePreview(); }
void KisDlgFilter::setFilter(KisFilterSP f) { Q_ASSERT(f); setDialogTitle(f); d->uiFilterDialog.filterSelection->setFilter(f); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(f->supportsAdjustmentLayers()); updatePreview(); }
KisRecordedAction* KisRecordedFilterActionFactory::fromXML(const QDomElement& elt, const KisRecordedActionLoadContext*) { QString name = elt.attribute("name"); KisNodeQueryPath pathnode = KisNodeQueryPath::fromString(elt.attribute("path")); const KisFilterSP filter = KisFilterRegistry::instance()->get(elt.attribute("filter")); if (filter) { KisFilterConfiguration* config = filter->defaultConfiguration(0); QDomElement paramsElt = elt.firstChildElement("Params"); if (config && !paramsElt.isNull()) { config->fromXML(paramsElt); } KisRecordedFilterAction* rfa = new KisRecordedFilterAction(name, pathnode, filter, config); delete config; return rfa; } else { return 0; } }
void KisFilterTest::testBlurFilterApplicationRect() { QRect filterRect(10,10,40,40); QRect src1Rect(5,5,50,50); QRect src2Rect(0,0,60,60); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); quint8 *whitePixel = new quint8[cs->pixelSize()]; cs->fromQColor(Qt::white, whitePixel); cs->setOpacity(whitePixel, OPACITY_OPAQUE_U8, 1); KisPaintDeviceSP src1 = new KisPaintDevice(cs); src1->fill(src1Rect.left(),src1Rect.top(),src1Rect.width(),src1Rect.height(), whitePixel); KisPaintDeviceSP src2 = new KisPaintDevice(cs); src2->fill(src2Rect.left(),src2Rect.top(),src2Rect.width(),src2Rect.height(), whitePixel); KisPaintDeviceSP dst1 = new KisPaintDevice(cs); KisPaintDeviceSP dst2 = new KisPaintDevice(cs); KisFilterSP f = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(f); KisFilterConfiguration * kfc = f->defaultConfiguration(0); Q_ASSERT(kfc); f->process(src1, dst1, 0, filterRect, kfc); f->process(src2, dst2, 0, filterRect, kfc); KisPaintDeviceSP reference = new KisPaintDevice(cs); reference->fill(filterRect.left(),filterRect.top(),filterRect.width(),filterRect.height(), whitePixel); QImage refImage = reference->convertToQImage(0,10,10,40,40); QImage dst1Image = dst1->convertToQImage(0,10,10,40,40); QImage dst2Image = dst2->convertToQImage(0,10,10,40,40); //dst1Image.save("DST1.png"); //dst2Image.save("DST2.png"); QPoint pt; QVERIFY(TestUtil::compareQImages(pt, refImage, dst1Image)); QVERIFY(TestUtil::compareQImages(pt, refImage, dst2Image)); }
void KisBlurBenchmark::benchmarkFilter() { KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); KisFilterConfiguration * kfc = filter->defaultConfiguration(m_device); // Get the predefined configuration from a file QFile file(QString(FILES_DATA_DIR) + QDir::separator() + filter->id() + ".cfg"); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { file.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream out(&file); out << kfc->toXML(); } else { QString s; QTextStream in(&file); s = in.readAll(); kfc->fromXML(s); } QBENCHMARK{ filter->process(m_device, QRect(0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT), kfc); } }
bool KisColorSpaceConvertVisitor::visit(KisAdjustmentLayer * layer) { // XXX: Make undoable! if (layer->filter()->name() == "perchannel") { // Per-channel filters need to be reset because of different number // of channels. This makes undo very tricky, but so be it. // XXX: Make this more generic for after 1.6, when we'll have many // channel-specific filters. KisFilterSP f = KisFilterRegistry::instance()->value("perchannel"); layer->setFilter(f->defaultConfiguration(0)); } KisLayerPropsCommand* propsCommand = new KisLayerPropsCommand(layer, layer->opacity(), layer->opacity(), layer->compositeOpId(), layer->compositeOpId(), layer->name(), layer->name(), m_emptyChannelFlags, m_emptyChannelFlags, false); m_image->undoAdapter()->addCommand(propsCommand); layer->resetCache(); return true; }
void KisImageTest::testConvertImageColorSpace() { const KoColorSpace *cs8 = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, 1000, 1000, cs8, "stest"); KisPaintDeviceSP device1 = new KisPaintDevice(cs8); KisLayerSP paint1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8, device1); KisFilterSP filter = KisFilterRegistry::instance()->value("blur"); Q_ASSERT(filter); KisFilterConfiguration *configuration = filter->defaultConfiguration(0); Q_ASSERT(configuration); KisLayerSP blur1 = new KisAdjustmentLayer(image, "blur1", configuration, 0); image->addNode(paint1, image->root()); image->addNode(blur1, image->root()); image->refreshGraph(); const KoColorSpace *cs16 = KoColorSpaceRegistry::instance()->rgb16(); image->lock(); image->convertImageColorSpace(cs16, KoColorConversionTransformation::InternalRenderingIntent, KoColorConversionTransformation::InternalConversionFlags); image->unlock(); QVERIFY(*cs16 == *image->colorSpace()); QVERIFY(*cs16 == *image->root()->colorSpace()); QVERIFY(*cs16 == *paint1->colorSpace()); QVERIFY(*cs16 == *blur1->colorSpace()); QVERIFY(!image->root()->compositeOp()); QVERIFY(*cs16 == *paint1->compositeOp()->colorSpace()); QVERIFY(*cs16 == *blur1->compositeOp()->colorSpace()); image->refreshGraph(); }
KisFilterStrokeStrategy::KisFilterStrokeStrategy(KisFilterSP filter, KisSafeFilterConfigurationSP filterConfig, KisResourcesSnapshotSP resources) : KisPainterBasedStrokeStrategy("FILTER_STROKE", filter->name(), resources, QVector<PainterInfo*>()), m_d(new Private()) { m_d->filter = filter; m_d->filterConfig = filterConfig; m_d->node = resources->currentNode(); m_d->updatesFacade = resources->image().data(); m_d->cancelSilently = false; m_d->secondaryTransaction = 0; enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE); }
void KisFilterOp::paintAt(const KisPaintInformation& info) { if (!painter()) { return; } KisFilterSP filter = settings->filter(); if (!filter) { return; } if (!source()) { return; } KisBrushSP brush = m_brush;; if (!brush) return; KisPaintInformation adjustedInfo = settings->m_optionsWidget->m_sizeOption->apply(info); if (! brush->canPaintFor(adjustedInfo)) return; double pScale = KisPaintOp::scaleForPressure(adjustedInfo.pressure()); // TODO: why is there scale and pScale that seems to contains the same things ? QPointF hotSpot = brush->hotSpot(pScale, pScale); QPointF pt = info.pos() - hotSpot; // Split the coordinates into integer plus fractional parts. The integer // is where the dab will be positioned and the fractional part determines // the sub-pixel positioning. qint32 x; double xFraction; qint32 y; double yFraction; splitCoordinate(pt.x(), &x, &xFraction); splitCoordinate(pt.y(), &y, &yFraction); double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure()); qint32 maskWidth = brush->maskWidth(scale, 0.0); qint32 maskHeight = brush->maskHeight(scale, 0.0); // Filter the paint device filter->process(KisConstProcessingInformation(source(), QPoint(x, y)), KisProcessingInformation(m_tmpDevice, QPoint(0, 0)), QSize(maskWidth, maskHeight), settings->filterConfig(), 0); // Apply the mask on the paint device (filter before mask because edge pixels may be important) KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_tmpDevice->colorSpace()); fixedDab->setRect(m_tmpDevice->extent()); fixedDab->initialize(); m_tmpDevice->readBytes(fixedDab->data(), fixedDab->bounds()); brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction); m_tmpDevice->writeBytes(fixedDab->data(), fixedDab->bounds()); if (!settings->ignoreAlpha()) { KisHLineIteratorPixel itTmpDev = m_tmpDevice->createHLineIterator(0, 0, maskWidth); KisHLineIteratorPixel itSrc = source()->createHLineIterator(x, y, maskWidth); const KoColorSpace* cs = m_tmpDevice->colorSpace(); for (int y = 0; y < maskHeight; ++y) { while (!itTmpDev.isDone()) { quint8 alphaTmpDev = cs->alpha(itTmpDev.rawData()); quint8 alphaSrc = cs->alpha(itSrc.rawData()); cs->setAlpha(itTmpDev.rawData(), qMin(alphaTmpDev, alphaSrc), 1); ++itTmpDev; ++itSrc; } itTmpDev.nextRow(); itSrc.nextRow(); } } // Blit the paint device onto the layer QRect dabRect = QRect(0, 0, maskWidth, maskHeight); QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); if (painter()->bounds().isValid()) { dstRect &= painter()->bounds(); } if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; qint32 sx = dstRect.x() - x; qint32 sy = dstRect.y() - y; qint32 sw = dstRect.width(); qint32 sh = dstRect.height(); painter()->bitBlt(dstRect.x(), dstRect.y(), m_tmpDevice, sx, sy, sw, sh); }
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; } }
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)); }