void KisKraLoaderTest::testLoading() { KisDocument *doc = KisPart::instance()->createDocument(); doc->loadNativeFormat(QString(FILES_DATA_DIR) + QDir::separator() + "load_test.kra"); KisImageSP image = doc->image(); image->lock(); QCOMPARE(image->nlayers(), 12); QCOMPARE(doc->documentInfo()->aboutInfo("title"), QString("test image for loading")); QCOMPARE(image->height(), 753); QCOMPARE(image->width(), 1000); QCOMPARE(image->colorSpace()->id(), KoColorSpaceRegistry::instance()->rgb8()->id()); KisNodeSP node = image->root()->firstChild(); QVERIFY(node); QCOMPARE(node->name(), QString("Background")); QVERIFY(node->inherits("KisPaintLayer")); node = node->nextSibling(); QVERIFY(node); QCOMPARE(node->name(), QString("Group 1")); QVERIFY(node->inherits("KisGroupLayer")); QCOMPARE((int) node->childCount(), 2); delete doc; }
QImage KritaShape::convertToQImage() { if (m_d->doc && m_d->doc->image()) { KisImageSP img = m_d->doc->image(); return img->convertToQImage(0, 0, img->width(), img->height(), m_d->displayProfile); } return QImage(); }
QImage utils::StrokeTester::doStroke(bool cancelled, bool indirectPainting, bool externalLayer, bool testUpdates, bool needQImage) { KisImageSP image = utils::createImage(0, m_imageSize); KoCanvasResourceManager *manager = utils::createResourceManager(image, 0, m_presetFilename); KisNodeSP currentNode; for (int i = 0; i < m_numIterations; i++) { modifyResourceManager(manager, image, i); KisPainter *painter = new KisPainter(); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image, image->rootLayer()->firstChild(), image->postExecutionUndoAdapter(), manager); if(externalLayer) { KisNodeSP externalNode = new KisPaintLayer(0, "extlyr", OPACITY_OPAQUE_U8, image->colorSpace()); resources->setCurrentNode(externalNode); Q_ASSERT(resources->currentNode() == externalNode); } initImage(image, resources->currentNode(), i); KisStrokeStrategy *stroke = createStroke(indirectPainting, resources, painter, image); m_strokeId = image->startStroke(stroke); addPaintingJobs(image, resources, painter, i); if(!cancelled) { image->endStroke(m_strokeId); } else { image->cancelStroke(m_strokeId); } image->waitForDone(); currentNode = resources->currentNode(); } QImage resultImage; if(needQImage) { KisPaintDeviceSP device = testUpdates ? image->projection() : currentNode->paintDevice(); resultImage = device->convertToQImage(0, 0, 0, image->width(), image->height()); } image = 0; delete manager; return resultImage; }
void KritaShape::paint(QPainter& painter, const KoViewConverter& converter) { if (m_d && m_d->doc && m_d->doc->image()) { // XXX: Only convert the bit the painter needs for painting? // Or should we keep a converted qimage in readiness, // just as with KisCanvas2? KisImageSP kimage = m_d->doc->image(); QImage qimg = kimage->convertToQImage(0, 0, kimage->width(), kimage->height(), m_d->displayProfile); // XXX: How about exposure? const QRectF paintRect = QRectF(QPointF(0.0, 0.0), size()); applyConversion(painter, converter); painter.drawImage(paintRect.toRect(), qimg); } else if (m_d->doc == 0) tryLoadFromImageData(dynamic_cast<KoImageData*>(KoShape::userData())); }
void KisDuplicateOp::paintAt(const KisPaintInformation& info) { if (!painter()) return; if (!m_duplicateStartIsSet) { m_duplicateStartIsSet = true; m_duplicateStart = info.pos(); } bool heal = settings->healing(); if (!source()) return; KisBrushSP brush = m_brush; if (!brush) return; if (! brush->canPaintFor(info)) return; double scale = KisPaintOp::scaleForPressure(info.pressure()); QPointF hotSpot = brush->hotSpot(scale, scale); 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); xFraction = yFraction = 0.0; QPointF srcPointF = pt - settings->offset(); QPoint srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()), y - static_cast<qint32>(settings->offset().y())); qint32 sw = brush->maskWidth(scale, 0.0); qint32 sh = brush->maskHeight(scale, 0.0); if (srcPoint.x() < 0) srcPoint.setX(0); if (srcPoint.y() < 0) srcPoint.setY(0); if (!(m_srcdev && !(*m_srcdev->colorSpace() == *source()->colorSpace()))) { m_srcdev = new KisPaintDevice(source()->colorSpace()); } Q_CHECK_PTR(m_srcdev); // Perspective correction ? KisPainter copyPainter(m_srcdev); KisImageSP image = settings->m_image; if (settings->perspectiveCorrection() && image && image->perspectiveGrid()->countSubGrids() == 1) { Matrix3qreal startM = Matrix3qreal::Identity(); Matrix3qreal endM = Matrix3qreal::Identity(); // First look for the grid corresponding to the start point KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin(); QRect r = QRect(0, 0, image->width(), image->height()); #if 1 if (subGridStart) { startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); } #endif #if 1 // Second look for the grid corresponding to the end point KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin(); if (subGridEnd) { endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); } #endif // Compute the translation in the perspective transformation space: QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart)); QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset())); QPointF translat = duplicateStartPositionT - positionStartPaintingT; KisRectIteratorPixel dstIt = m_srcdev->createRectIterator(0, 0, sw, sh); KisRandomSubAccessorPixel srcAcc = source()->createRandomSubAccessor(); //Action while (!dstIt.isDone()) { if (dstIt.isSelected()) { QPointF p = KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt.x() + x, dstIt.y() + y)) + translat); srcAcc.moveTo(p); srcAcc.sampledOldRawData(dstIt.rawData()); } ++dstIt; } } else { // Or, copy the source data on the temporary device: copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.bitBlt(0, 0, source(), srcPoint.x(), srcPoint.y(), sw, sh); copyPainter.end(); } // heal ? if (heal) { quint16 dataDevice[4]; quint16 dataSrcDev[4]; double* matrix = new double[ 3 * sw * sh ]; // First divide const KoColorSpace* deviceCs = source()->colorSpace(); KisHLineConstIteratorPixel deviceIt = source()->createHLineConstIterator(x, y, sw); KisHLineIteratorPixel srcDevIt = m_srcdev->createHLineIterator(0, 0, sw); double* matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; !srcDevIt.isDone(); i++) { deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1); deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1); // Division for (int k = 0; k < 3; k++) { matrixIt[k] = dataDevice[k] / (double)qMax((int)dataSrcDev [k], 1); } ++deviceIt; ++srcDevIt; matrixIt += 3; } deviceIt.nextRow(); srcDevIt.nextRow(); } // Minimize energy { int iter = 0; double err; double* solution = new double [ 3 * sw * sh ]; do { err = minimizeEnergy(&matrix[0], &solution[0], sw, sh); memcpy(&matrix[0], &solution[0], sw * sh * 3 * sizeof(double)); iter++; } while (err < 0.00001 && iter < 100); delete [] solution; } // Finaly multiply deviceIt = source()->createHLineIterator(x, y, sw); srcDevIt = m_srcdev->createHLineIterator(0, 0, sw); matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; !srcDevIt.isDone(); i++) { deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1); deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1); // Multiplication for (int k = 0; k < 3; k++) { dataSrcDev[k] = (int)CLAMP(matrixIt[k] * qMax((int) dataSrcDev[k], 1), 0, 65535); } deviceCs->fromLabA16((quint8*)dataSrcDev, srcDevIt.rawData(), 1); ++deviceIt; ++srcDevIt; matrixIt += 3; } deviceIt.nextRow(); srcDevIt.nextRow(); } delete [] matrix; } KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_srcdev->colorSpace()); fixedDab->setRect(QRect(0, 0, sw, sh)); fixedDab->initialize(); m_srcdev->readBytes(fixedDab->data(), fixedDab->bounds()); brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction); m_srcdev->writeBytes(fixedDab->data(), fixedDab->bounds()); QRect dabRect = QRect(0, 0, brush->maskWidth(scale, 0.0), brush->maskHeight(scale, 0.0)); 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; sw = dstRect.width(); sh = dstRect.height(); painter()->bitBlt(dstRect.x(), dstRect.y(), m_srcdev, 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; } }