KisHairyPaintOp::KisHairyPaintOp(const KisBrushBasedPaintOpSettings *settings, KisPainter * painter, KisNodeSP node, KisImageSP image)
    : KisPaintOp(painter)
{
    Q_UNUSED(image)
    Q_ASSERT(settings);

    m_dev = node ? node->paintDevice() : 0;

    KisBrushOption brushOption;
    brushOption.readOptionSetting(settings);
    KisBrushSP brush = brushOption.brush();
    KisFixedPaintDeviceSP dab = cachedDab(painter->device()->compositionSourceColorSpace());
    if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
        dab = brush->paintDevice(source()->colorSpace(), 1.0, 0.0, KisPaintInformation());
    }
    else {
        brush->mask(dab, painter->paintColor(), 1.0, 1.0, 0.0, KisPaintInformation());
    }

    m_brush.fromDabWithDensity(dab, settings->getDouble(HAIRY_BRISTLE_DENSITY) * 0.01);
    m_brush.setInkColor(painter->paintColor());

    loadSettings(settings);
    m_brush.setProperties(&m_properties);

    m_rotationOption.readOptionSetting(settings);
    m_opacityOption.readOptionSetting(settings);
    m_sizeOption.readOptionSetting(settings);
    m_rotationOption.resetAllSensors();
    m_opacityOption.resetAllSensors();
    m_sizeOption.resetAllSensors();
}
Exemple #2
0
KisBrushSP KisAutoBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition)
{
    KisMaskGenerator* mask = KisMaskGenerator::fromXML(brushDefinition.firstChildElement("MaskGenerator"));
    bool result;
    QLocale c(QLocale::German);

    double angle = brushDefinition.attribute("angle", "0.0").toDouble(&result);
    if (!result) {
        angle = c.toDouble(brushDefinition.attribute("angle"));
    }

    double randomness = brushDefinition.attribute("randomness", "0.0").toDouble(&result);
    if (!result) {
        randomness = c.toDouble(brushDefinition.attribute("randomness"));
    }

    qreal density = brushDefinition.attribute("density", "1.0").toDouble(&result);
    if (!result) {
        density = c.toDouble(brushDefinition.attribute("density"));
    }

    double spacing = brushDefinition.attribute("spacing", "1.0").toDouble(&result);
    if (!result) {
        spacing = c.toDouble(brushDefinition.attribute("spacing"));
    }

    KisBrushSP brush = new KisAutoBrush(mask, angle, randomness, density);
    brush->setSpacing(spacing);
    return brush;
}
QPainterPath KisBrushBasedPaintOpSettings::brushOutlineImpl(const KisPaintInformation &info,
                                                            OutlineMode mode,
                                                            qreal additionalScale,
                                                            bool forceOutline)
{
    QPainterPath path;

    if (forceOutline || mode == CursorIsOutline || mode == CursorIsCircleOutline || mode == CursorTiltOutline) {
        KisBrushSP brush = this->brush();
        if (!brush) return path;
        qreal finalScale = brush->scale() * additionalScale;

        QPainterPath realOutline = brush->outline();

        if (mode == CursorIsCircleOutline || mode == CursorTiltOutline ||
            (forceOutline && mode == CursorNoOutline)) {

            QPainterPath ellipse;
            ellipse.addEllipse(realOutline.boundingRect());
            realOutline = ellipse;
        }

        path = outlineFetcher()->fetchOutline(info, this, realOutline, finalScale, brush->angle());

        if (mode == CursorTiltOutline) {
            QPainterPath tiltLine = makeTiltIndicator(info,
                realOutline.boundingRect().center(),
                realOutline.boundingRect().width() * 0.5,
                3.0);
            path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, finalScale, 0.0, true, realOutline.boundingRect().center().x(), realOutline.boundingRect().center().y()));
        }
    }

    return path;
}
Exemple #4
0
static void dabSizeHelper(KisBrushSP const& brush,
    QString const& name, KisDabShape const& shape, int expectedWidth, int expectedHeight)
{
    qDebug() << name;
    QCOMPARE(brush->maskWidth(shape, 0.0, 0.0, KisPaintInformation()), expectedWidth);
    QCOMPARE(brush->maskHeight(shape, 0.0, 0.0, KisPaintInformation()), expectedHeight);
}
KisBrushSP KisPredefinedBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition)
{
    KoResourceServer<KisBrush> *rServer = KisBrushServer::instance()->brushServer();
    QString brushFileName = brushDefinition.attribute("filename", "");
    KisBrushSP brush = rServer->resourceByFilename(brushFileName);

    //Fallback for files that still use the old format
    if(!brush) {
        QFileInfo info(brushFileName);
        brush = rServer->resourceByFilename(info.fileName());
    }

    if(!brush) {
        brush = rServer->resources().first();
    }

    Q_ASSERT(brush);

    double spacing = brushDefinition.attribute("spacing", "0.25").toDouble();
    brush->setSpacing(spacing);

    double angle = brushDefinition.attribute("angle", "0.0").toDouble();
    brush->setAngle(angle);

    double scale = brushDefinition.attribute("scale", "1.0").toDouble();
    brush->setScale(scale);

    return brush;
}
Exemple #6
0
KisBrushSP KisAutoBrushFactory::getOrCreateBrush( const QDomElement& brushDefinition )
{
    KisMaskGenerator* mask = KisMaskGenerator::fromXML(brushDefinition);
    KisBrushSP brush = new KisAutoBrush( mask );
    double spacing = brushDefinition.attribute("brush_spacing", "1.0").toDouble();
    brush->setSpacing( spacing );
    return brush;
}
Exemple #7
0
KisBrushSP KisBrush::fromXML(const QDomElement& element)
{
    KisBrushSP brush = KisBrushRegistry::instance()->getOrCreateBrush(element);
    if (brush && element.attribute("BrushVersion", "1") == "1") {
        brush->setScale(brush->scale() * 2.0);
    }
    return brush;
}
Exemple #8
0
QRectF KisDuplicateOpSettings::paintOutlineRect(const QPointF& pos, KisImageSP image) const
{
    KisBrushSP brush = m_optionsWidget->m_brushOption->brush();
    QPointF hotSpot = brush->hotSpot(1.0, 1.0);
    QRectF rect = image->pixelToDocument(QRect(0,0, brush->width(), brush->height()) );
    rect.translate( pos - hotSpot + QPoint(1,1) );
    rect |= duplicateOutlineRect(pos, image);
    return rect;
}
Exemple #9
0
void KisDuplicateOpSettings::paintOutline(const QPointF& pos, KisImageSP image, QPainter &painter, const KoViewConverter &converter) const
{
    KisBrushSP brush = m_optionsWidget->m_brushOption->brush();
    QPointF hotSpot = brush->hotSpot(1.0, 1.0);
    painter.setPen(Qt::black);
    painter.setBackground(Qt::black);
    painter.drawEllipse( converter.documentToView( image->pixelToDocument(QRect(0,0, brush->width(), brush->height()) ).translated( pos - hotSpot + QPoint(1,1) ) ) );
    
    QRectF rect2 = converter.documentToView( duplicateOutlineRect( pos, image ) );
    painter.drawLine(rect2.topLeft(), rect2.bottomRight() );
    painter.drawLine(rect2.topRight(), rect2.bottomLeft() );

}
Exemple #10
0
void KisAutoBrushTest::testMaskGeneration()
{
    KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 1.0, 1.0, 1.0, 2, false);
    KisBrushSP a = new KisAutoBrush(circle, 0.0, 0.0);
    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();

    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);

    // check masking an existing paint device
    KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs);
    fdev->setRect(QRect(0, 0, 100, 100));
    fdev->initialize();
    cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100);

    QPoint errpoint;
    QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_1.png");
    QImage image = fdev->convertToQImage(0);

    if (!TestUtil::compareQImages(errpoint, image, result)) {
        image.save("kis_autobrush_test_1.png");
        QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
    }

    // Check creating a mask dab with a single color
    fdev = new KisFixedPaintDevice(cs);
    a->mask(fdev, KoColor(Qt::black, cs), KisDabShape(), info);

    result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_3.png");
    image = fdev->convertToQImage(0);
    if (!TestUtil::compareQImages(errpoint, image, result)) {
        image.save("kis_autobrush_test_3.png");
        QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
    }

    // Check creating a mask dab with a color taken from a paint device
    KoColor red(Qt::red, cs);
    cs->setOpacity(red.data(), quint8(128), 1);
    KisPaintDeviceSP dev = new KisPaintDevice(cs);
    dev->fill(0, 0, 100, 100, red.data());

    fdev = new KisFixedPaintDevice(cs);
    a->mask(fdev, dev, KisDabShape(), info);

    result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_4.png");
    image = fdev->convertToQImage(0);
    if (!TestUtil::compareQImages(errpoint, image, result)) {
        image.save("kis_autobrush_test_4.png");
        QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1());
    }

}
Exemple #11
0
QPainterPath KisBrushBasedPaintOpSettings::brushOutline(const KisPaintInformation &info, OutlineMode mode) const
{
    if (mode != CursorIsOutline) return QPainterPath();

    KisBrushBasedPaintopOptionWidget *widget = dynamic_cast<KisBrushBasedPaintopOptionWidget*>(optionsWidget());

    if (!widget) {
        return KisPaintOpSettings::brushOutline(info, mode);
    }

    KisBrushSP brush = widget->brush();

    return outlineFetcher()->fetchOutline(info, this, brush->outline(), brush->scale(), brush->angle());
}
KisBrushSP KisAbrBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition)
{
    KoResourceServer<KisBrush>* rServer = KisBrushServer::instance()->brushServer();
    QString brushName = brushDefinition.attribute("name", "test_1");
    
    KisBrushSP brush = rServer->getResourceByName(brushName);
    if (!brush){
        return 0;
    }
    
    double spacing = brushDefinition.attribute("spacing", "0.25").toDouble();
    brush->setSpacing(spacing);

    return brush;

}
Exemple #13
0
void KisAutoBrushTest::testDabSize()
{
    KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 0.5, 1.0, 1.0, 2, false);
    KisBrushSP a = new KisAutoBrush(circle, 0.0, 0.0);
    QCOMPARE(a->width(), 10);
    QCOMPARE(a->height(), 5);

    dabSizeHelper(a, "Identity",  KisDabShape(),                        10,  5);
    dabSizeHelper(a, "Double",    KisDabShape(2.0, 1.0, 0.0),           20, 10);
    dabSizeHelper(a, "Halve",     KisDabShape(0.5, 1.0, 0.0),            5,  3);
    dabSizeHelper(a, "180 deg",   KisDabShape(1.0, 1.0, M_PI),          10,  5);
    dabSizeHelper(a, "90 deg",    KisDabShape(1.0, 1.0, M_PI_2),         6, 10); // ceil rule
    dabSizeHelper(a, "-90 deg",   KisDabShape(1.0, 1.0, -M_PI_2),        6, 11); // ceil rule
    dabSizeHelper(a, "45 deg",    KisDabShape(1.0, 1.0, 0.25 * M_PI),   11, 11);
    dabSizeHelper(a, "2x, 45d",   KisDabShape(2.0, 1.0, 0.25 * M_PI),   22, 22);
    dabSizeHelper(a, "0.5x, 45d", KisDabShape(0.5, 1.0, 0.25 * M_PI),    6, 6);
    dabSizeHelper(a, "0.5x, 45d", KisDabShape(0.5, 1.0, 0.25 * M_PI),    6, 6);
    dabSizeHelper(a, "0.5y",      KisDabShape(1.0, 0.5, 0.0),           10, 5);
}
Exemple #14
0
void KisBrushSelectionWidget::setCurrentBrush( KisBrushSP brush)
{
    // XXX: clever code have brush plugins know their configuration
    //      pane, so we don't have to have this if statement and
    //      have an extensible set of brush types
    if ( dynamic_cast<KisAutoBrush*>(brush.data()) ) {
        m_brushesTab->setCurrentWidget( m_autoBrushWidget );
        m_autoBrushWidget->setBrush(brush);
    }
    else if (dynamic_cast<KisTextBrush*>(brush.data())) {
        m_brushesTab->setCurrentWidget( m_textBrushWidget );
        m_textBrushWidget->setBrush(brush);
    }
    else {
        m_brushesTab->setCurrentWidget( m_brushChooser );
        m_brushChooser->setBrush(brush);
    }

}
Exemple #15
0
void KisAutoBrushWidget::setBrush(KisBrushSP brush)
{
    m_autoBrush = brush;
    m_brush = brush->image();
    // XXX: lock, set and unlock the widgets.
    KisAutoBrush* aBrush = dynamic_cast<KisAutoBrush*>(brush.data());
    if (aBrush->maskGenerator()->type() == KisMaskGenerator::CIRCLE) {
        comboBoxShape->setCurrentIndex(0);
    }
    else if (aBrush->maskGenerator()->type() == KisMaskGenerator::RECTANGLE) {
        comboBoxShape->setCurrentIndex(1);
    }
    else {
        comboBoxShape->setCurrentIndex(2);
    }

    comboBoxMaskType->setCurrentIndex(comboBoxMaskType->findText(aBrush->maskGenerator()->name()));


    inputRadius->setValue(aBrush->maskGenerator()->diameter());
    inputRatio->setValue(aBrush->maskGenerator()->ratio());

    inputVFade->blockSignals(true);
    inputHFade->blockSignals(true);
    inputHFade->setValue(aBrush->maskGenerator()->horizontalFade());
    inputVFade->setValue(aBrush->maskGenerator()->verticalFade());
    inputVFade->blockSignals(false);
    inputHFade->blockSignals(false);

    inputAngle->setValue(aBrush->angle() * 180 / M_PI);
    inputSpikes->setValue(aBrush->maskGenerator()->spikes());
    inputSpacing->setValue(aBrush->spacing());
    inputSpacing->setExponentRatio(3.0);
    inputRandomness->setValue(aBrush->randomness() * 100);
    density->setValue(aBrush->density() * 100);

    if (!aBrush->maskGenerator()->curveString().isEmpty()) {
        KisCubicCurve curve;
        curve.fromString(aBrush->maskGenerator()->curveString());
        softnessCurve->setCurve(curve);
    }
}
Exemple #16
0
void KisAutoBrushTest::testClone()
{
    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();

    KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 0.7, 0.85, 0.5, 2, true);
    KisBrushSP brush = new KisAutoBrush(circle, 0.5, 0.0);

    KisPaintInformation info(QPointF(100.0, 100.0), 0.5);

    KisFixedPaintDeviceSP fdev1 = new KisFixedPaintDevice(cs);
    brush->mask(fdev1, KoColor(Qt::black, cs), KisDabShape(0.8, 1.0, 8.0), info);
    QImage res1 = fdev1->convertToQImage(0);

    KisBrushSP clone = brush->clone();

    KisFixedPaintDeviceSP fdev2 = new KisFixedPaintDevice(cs);
    clone->mask(fdev2, KoColor(Qt::black, cs), KisDabShape(0.8, 1.0, 8.0), info);
    QImage res2 = fdev2->convertToQImage(0);

    QCOMPARE(res1, res2);
}
Exemple #17
0
void KisBrushOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()->device()) return;

    KisBrushSP brush = m_brush;
    Q_ASSERT(brush);
    if (!brush) return;

    KisPaintInformation adjustedInfo = settings->m_optionsWidget->m_sizeOption->apply(info);
    if (!brush->canPaintFor(adjustedInfo))
        return;

    KisPaintDeviceSP device = painter()->device();

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

    quint8 origOpacity = settings->m_optionsWidget->m_opacityOption->apply(painter(), info.pressure());
    KoColor origColor = settings->m_optionsWidget->m_darkenOption->apply(painter(), info.pressure());

    double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());

    KisFixedPaintDeviceSP dab = cachedDab(device->colorSpace());
    if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
        dab = brush->image(device->colorSpace(), scale, 0.0, adjustedInfo, xFraction, yFraction);
    } else {
        KoColor color = painter()->paintColor();
        color.convertTo(dab->colorSpace());
        brush->mask(dab, color, scale, scale, 0.0, info, xFraction, yFraction);
    }

    painter()->bltFixed(QPoint(x, y), dab, dab->bounds());
    painter()->setOpacity(origOpacity);
    painter()->setPaintColor(origColor);

}
Exemple #18
0
void KisSmudgeOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()->device()) return;

    KisBrushSP brush = m_brush;

    Q_ASSERT(brush);
    if (!brush) return;

    KisPaintInformation adjustedInfo = settings->m_optionsWidget->m_sizeOption->apply(info);
    if (! brush->canPaintFor(adjustedInfo))
        return;

    KisPaintDeviceSP device = painter()->device();
    double pScale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());
    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);

    KisFixedPaintDeviceSP dab = 0;

    double scale = KisPaintOp::scaleForPressure(adjustedInfo.pressure());

    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 (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;

    if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
        dab = brush->image(device->colorSpace(), pScale, 0.0, adjustedInfo, xFraction, yFraction);
        dab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
    } else {
        dab = cachedDab();
        KoColor color = painter()->paintColor();
        dab->convertTo(KoColorSpaceRegistry::instance()->alpha8());
        brush->mask(dab, color, scale, pScale, 0.0, info, xFraction, yFraction);
    }

    qint32 sw = dab->bounds().width();
    qint32 sh = dab->bounds().height();

    /* To smudge, one does the following:
         * at first, initialize a temporary paint device with a copy of the original (dab-sized piece, really).
         * all other times:
             reduce the transparency of the temporary paint device so as to let it mix gradually
         * combine the temp device with the piece the brush currently is 'painting', according to a mix (opacity)
             note that in the first step, this does the actual copying of the data
         * this combination is then composited upon the actual image
       TODO: what happened exactly in 1.6 (and should happen now) when the dab resizes halfway due to pressure?
    */
    int opacity = OPACITY_OPAQUE;
    if (!m_firstRun) {
        opacity = settings->m_optionsWidget->m_rateOption->apply( opacity, sw, sh, m_srcdev, info.pressure() );

        KisRectIterator it = m_srcdev->createRectIterator(0, 0, sw, sh);
        KoColorSpace* cs = m_srcdev->colorSpace();
        while(!it.isDone()) {
            cs->setAlpha(it.rawData(), (cs->alpha(it.rawData()) * opacity) / OPACITY_OPAQUE, 1);
            ++it;
        }

        opacity = OPACITY_OPAQUE - opacity;
    } else {
        m_firstRun = false;
    }

    KisPainter copyPainter(m_srcdev);
    copyPainter.setOpacity(opacity);
    copyPainter.bitBlt(0, 0, device, pt.x(), pt.y(), sw, sh);
    copyPainter.end();

    m_target = new KisPaintDevice(device->colorSpace());

    // Looks hacky, but we lost bltMask, or the ability to easily convert alpha8 paintdev to selection?
    KisSelectionSP dabAsSelection = new KisSelection();
    copyPainter.begin(dabAsSelection);
    copyPainter.setOpacity(OPACITY_OPAQUE);
    copyPainter.setCompositeOp(COMPOSITE_COPY);
    copyPainter.bltFixed(0, 0, dab, 0, 0, sw, sh);
    copyPainter.end();

    copyPainter.begin(m_target);
    copyPainter.setCompositeOp(COMPOSITE_OVER);
    copyPainter.setSelection(dabAsSelection);
    copyPainter.bitBlt(0, 0, m_srcdev, 0, 0, sw, sh);
    copyPainter.end();

    qint32 sx = dstRect.x() - x;
    qint32 sy = dstRect.y() - y;
    sw = dstRect.width();
    sh = dstRect.height();

    painter()->bitBlt(dstRect.x(), dstRect.y(), m_target, sx, sy, sw, sh);

}
Exemple #19
0
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);


}
KisSpacingInformation KisDuplicateOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()->device()) return 1.0;

    KisBrushSP brush = m_brush;
    if (!brush)
        return 1.0;

    if (!brush->canPaintFor(info))
        return 1.0;

    if (!m_duplicateStartIsSet) {
        m_duplicateStartIsSet = true;
        m_duplicateStart = info.pos();
    }

    KisPaintDeviceSP realSourceDevice = settings->node()->paintDevice();

    qreal scale = m_sizeOption.apply(info);
    if (checkSizeTooSmall(scale)) return KisSpacingInformation();

    QPointF hotSpot = brush->hotSpot(scale, scale, 0, info);
    QPointF pt = info.pos() - hotSpot;

    setCurrentScale(scale);

    // 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, y;
    qreal xFraction, yFraction; // will not be used
    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);

    QPoint srcPoint;

    if(m_moveSourcePoint)
    {
        srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()),
                          y - static_cast<qint32>(settings->offset().y()));
    } else {
        srcPoint = QPoint(static_cast<qint32>(settings->position().x() - hotSpot.x()),
                          static_cast<qint32>(settings->position().y() - hotSpot.y()));
    }

    qint32 sw = brush->maskWidth(scale, 0.0, xFraction, yFraction, info);
    qint32 sh = brush->maskHeight(scale, 0.0, xFraction, yFraction, info);

    if (srcPoint.x() < 0)
        srcPoint.setX(0);

    if (srcPoint.y() < 0)
        srcPoint.setY(0);

    // Perspective correction ?
    KisImageWSP image = settings->m_image;
    if (m_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;

        KisRectIteratorSP dstIt = m_srcdev->createRectIteratorNG(0, 0, sw, sh);
        KisRandomSubAccessorSP srcAcc = realSourceDevice->createRandomSubAccessor();
        //Action
        do {
            QPointF p =  KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt->x() + x, dstIt->y() + y)) + translat);
            srcAcc->moveTo(p);
            srcAcc->sampledOldRawData(dstIt->rawData());
        } while (dstIt->nextPixel());


    } else {
        KisPainter copyPainter(m_srcdev);
        copyPainter.setCompositeOp(COMPOSITE_COPY);
        copyPainter.bitBltOldData(0, 0, realSourceDevice, srcPoint.x(), srcPoint.y(), sw, sh);
        copyPainter.end();
    }

    // heal ?

    if (m_healing) {
        quint16 srcData[4];
        quint16 tmpData[4];
        qreal* matrix = new qreal[ 3 * sw * sh ];
        // First divide
        const KoColorSpace* srcCs = realSourceDevice->colorSpace();
        const KoColorSpace* tmpCs = m_srcdev->colorSpace();
        KisHLineConstIteratorSP srcIt = realSourceDevice->createHLineConstIteratorNG(x, y, sw);
        KisHLineIteratorSP tmpIt = m_srcdev->createHLineIteratorNG(0, 0, sw);
        qreal* matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; i < sw; i++) {
                srcCs->toLabA16(srcIt->oldRawData(), (quint8*)srcData, 1);
                tmpCs->toLabA16(tmpIt->rawData(), (quint8*)tmpData, 1);
                // Division
                for (int k = 0; k < 3; k++) {
                    matrixIt[k] = srcData[k] / (qreal)qMax((int)tmpData [k], 1);
                }
                srcIt->nextPixel();
                tmpIt->nextPixel();
                matrixIt += 3;
            }
            srcIt->nextRow();
            tmpIt->nextRow();
        }
        // Minimize energy
        {
            int iter = 0;
            qreal err;
            qreal* solution = new qreal [ 3 * sw * sh ];
            do {
                err = minimizeEnergy(&matrix[0], &solution[0], sw, sh);

                // swap pointers
                qreal *tmp = matrix;
                matrix = solution;
                solution = tmp;

                iter++;
            } while (err > 0.00001 && iter < 100);
            delete [] solution;
        }

        // Finaly multiply
        KisHLineIteratorSP srcIt2 = realSourceDevice->createHLineIteratorNG(x, y, sw);
        KisHLineIteratorSP tmpIt2 = m_srcdev->createHLineIteratorNG(0, 0, sw);
        matrixIt = &matrix[0];
        for (int j = 0; j < sh; j++) {
            for (int i = 0; i < sw; i++) {
                srcCs->toLabA16(srcIt2->rawData(), (quint8*)srcData, 1);
                tmpCs->toLabA16(tmpIt2->rawData(), (quint8*)tmpData, 1);
                // Multiplication
                for (int k = 0; k < 3; k++) {
                    tmpData[k] = (int)CLAMP(matrixIt[k] * qMax((int) tmpData[k], 1), 0, 65535);
                }
                tmpCs->fromLabA16((quint8*)tmpData, tmpIt2->rawData(), 1);
                srcIt2->nextPixel();
                tmpIt2->nextPixel();
                matrixIt += 3;
            }
            srcIt2->nextRow();
            tmpIt2->nextRow();
        }
        delete [] matrix;
    }

    static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
    static KoColor color(Qt::black, cs);

    KisFixedPaintDeviceSP dab =
        m_dabCache->fetchDab(cs, color, scale, scale,
                             0.0, info);

    QRect dstRect = QRect(x, y, dab->bounds().width(), dab->bounds().height());
    if (dstRect.isEmpty()) return 1.0;

    painter()->bitBltWithFixedSelection(dstRect.x(), dstRect.y(),
                                        m_srcdev, dab,
                                        dstRect.width(),
                                        dstRect.height());

    painter()->renderMirrorMaskSafe(dstRect, m_srcdev, 0, 0, dab,
                                    !m_dabCache->needSeparateOriginal());

    return effectiveSpacing(dstRect.width(), dstRect.height());
}
Exemple #21
0
KisSpacingInformation KisColorSmudgeOp::paintAt(const KisPaintInformation& info)
{
    KisBrushSP brush = m_brush;

    // Simple error catching
    if (!painter()->device() || !brush || !brush->canPaintFor(info))
        return 1.0;

    // get the scaling factor calculated by the size option
    qreal scale    = m_sizeOption.apply(info);
    qreal rotation = m_rotationOption.apply(info);

    if (checkSizeTooSmall(scale)) return KisSpacingInformation();

    setCurrentScale(scale);
    setCurrentRotation(rotation);

    QPointF scatteredPos =
        m_scatterOption.apply(info,
                              brush->maskWidth(scale, rotation, 0, 0, info),
                              brush->maskHeight(scale, rotation, 0, 0, info));

    QPointF hotSpot = brush->hotSpot(scale, scale, rotation, info);

    /**
     * Update the brush mask.
     *
     * Upon leaving the function:
     *   o m_maskDab stores the new mask
     *   o m_maskBounds stroes the extents of the mask paint device
     *   o m_dstDabRect stores the destination rect where the mask is going
     *     to be written to
     */
    updateMask(info, scale, rotation, scatteredPos);

    QPointF newCenterPos = QRectF(m_dstDabRect).center();
    QRect srcDabRect = m_dstDabRect.translated((m_lastPaintPos - newCenterPos).toPoint());


    /**
     * Save the center of the current dab to know where to read the
     * data during the next pass. We do not save scatteredPos here,
     * because it may slightly differ from the real center of the
     * brush (due to some rounding effects), which will result in
     * really weird quality.
     */
    m_lastPaintPos = QRectF(m_dstDabRect).center();

    KisSpacingInformation spacingInfo =
        effectiveSpacing(m_dstDabRect.width(), m_dstDabRect.height(),
                         m_spacingOption, info);

    if (m_firstRun) {
        m_firstRun = false;
        return spacingInfo;
    }


    // save the old opacity value and composite mode
    quint8               oldOpacity = painter()->opacity();
    QString              oldModeId = painter()->compositeOp()->id();
    qreal                fpOpacity  = (qreal(oldOpacity) / 255.0) * m_opacityOption.getOpacityf(info);

    KoColor color = painter()->paintColor();

    if (m_image && m_overlayModeOption.isChecked()) {
        m_image->blockUpdates();
        m_backgroundPainter->bitBlt(QPoint(), m_image->projection(), srcDabRect);
        m_image->unblockUpdates();
    }
    else {
        // IMPORTANT: clear the temporary painting device to color black with zero opacity
        //            it will only clear the extents of the brush
        m_tempDev->clear(QRect(QPoint(), m_dstDabRect.size()));
    }

    if (m_smudgeRateOption.getMode() == KisSmudgeOption::SMEARING_MODE) {
        // cut out the area from the canvas under the brush
        // and blit it to the temporary painting device
        if(m_smudgeRadiusOption.isChecked())
        {
            m_smudgeRadiusOption.apply(*m_smudgePainter,info,m_brush->width(),m_dstDabRect.center().x(),m_dstDabRect.center().y(),painter()->device());
            color = m_smudgePainter->paintColor();

        }
        m_smudgePainter->bitBlt(QPoint(), painter()->device(), srcDabRect);
    }
    else {
        QPoint pt = (srcDabRect.topLeft() + hotSpot).toPoint();
        // get the pixel on the canvas that lies beneath the hot spot
        // of the dab and fill  the temporary paint device with that color

        KoColor color = painter()->paintColor();



        if(m_smudgeRadiusOption.isChecked())
        {
            m_smudgeRadiusOption.apply(*m_smudgePainter,info,m_brush->width(),pt.x(),pt.y(),painter()->device());
            KoColor color2 =  m_smudgePainter->paintColor();
            m_smudgePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(),color2);

        }

        else
        {
            KisCrossDeviceColorPickerInt colorPicker(painter()->device(), color);
             colorPicker.pickColor(pt.x(), pt.y(), color.data());

             m_smudgePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color);

        }


    }

    // if the user selected the color smudge option
    // we will mix some color into the temporary painting device (m_tempDev)
    if (m_colorRateOption.isChecked()) {
        // this will apply the opacy (selected by the user) to copyPainter
        // (but fit the rate inbetween the range 0.0 to (1.0-SmudgeRate))
        qreal maxColorRate = qMax<qreal>(1.0 - m_smudgeRateOption.getRate(), 0.2);
        m_colorRateOption.apply(*m_colorRatePainter, info, 0.0, maxColorRate, fpOpacity);

        // paint a rectangle with the current color (foreground color)
        // or a gradient color (if enabled)
        // into the temporary painting device and use the user selected
        // composite mode
        KoColor color = painter()->paintColor();
        m_gradientOption.apply(color, m_gradient, info);
        m_colorRatePainter->fill(0, 0, m_dstDabRect.width(), m_dstDabRect.height(), color);
        
    }


    // if color is disabled (only smudge) and "overlay mode is enabled
    // then first blit the region under the brush from the image projection
    // to the painting device to prevent a rapid build up of alpha value
    // if the color to be smudged is semi transparent
    if (m_image && m_overlayModeOption.isChecked() && !m_colorRateOption.isChecked()) {
        painter()->setCompositeOp(COMPOSITE_COPY);
        painter()->setOpacity(OPACITY_OPAQUE_U8);
        m_image->blockUpdates();
        painter()->bitBlt(m_dstDabRect.topLeft(), m_image->projection(), m_dstDabRect);
        m_image->unblockUpdates();
    }


    // set opacity calculated by the rate option
    m_smudgeRateOption.apply(*painter(), info, 0.0, 1.0, fpOpacity);

    // then blit the temporary painting device on the canvas at the current brush position
    // the alpha mask (maskDab) will be used here to only blit the pixels that are in the area (shape) of the brush
    painter()->setCompositeOp(COMPOSITE_COPY);
    painter()->bitBltWithFixedSelection(m_dstDabRect.x(), m_dstDabRect.y(), m_tempDev, m_maskDab, m_dstDabRect.width(), m_dstDabRect.height());
    painter()->renderMirrorMaskSafe(m_dstDabRect, m_tempDev, 0, 0, m_maskDab,
                                    !m_dabCache->needSeparateOriginal());

    // restore orginal opacy and composite mode values
    painter()->setOpacity(oldOpacity);
    painter()->setCompositeOp(oldModeId);



    return spacingInfo;
}
KisSpacingInformation KisFilterOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) {
        return KisSpacingInformation(1.0);
    }

    if (!m_filter) {
        return KisSpacingInformation(1.0);
    }

    if (!source()) {
        return KisSpacingInformation(1.0);
    }

    KisBrushSP brush = m_brush;
    if (!brush) return KisSpacingInformation(1.0);

    if (! brush->canPaintFor(info))
        return KisSpacingInformation(1.0);

    qreal scale = m_sizeOption.apply(info);
    if (checkSizeTooSmall(scale)) return KisSpacingInformation();

    setCurrentScale(scale);

    qreal rotation = m_rotationOption.apply(info);

    static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8();
    static KoColor color(Qt::black, cs);

    QRect dstRect;
    KisFixedPaintDeviceSP dab =
        m_dabCache->fetchDab(cs, color, info.pos(),
                             scale, scale, rotation,
                             info, 1.0,
                             &dstRect);

    if (dstRect.isEmpty()) return KisSpacingInformation(1.0);

    QRect dabRect = dab->bounds();

    // sanity check
    Q_ASSERT(dstRect.size() == dabRect.size());


    // Filter the paint device
    QRect neededRect = m_filter->neededRect(dstRect, m_filterConfiguration);

    KisPainter p(m_tmpDevice);
    if (!m_smudgeMode) {
        p.setCompositeOp(COMPOSITE_COPY);
    }
    p.bitBltOldData(neededRect.topLeft() - dstRect.topLeft(), source(), neededRect);

    KisTransaction transaction(m_tmpDevice);
    m_filter->process(m_tmpDevice, dabRect, m_filterConfiguration, 0);
    transaction.end();


    painter()->
    bitBltWithFixedSelection(dstRect.x(), dstRect.y(),
                             m_tmpDevice, dab,
                             0, 0,
                             dabRect.x(), dabRect.y(),
                             dabRect.width(), dabRect.height());

    painter()->renderMirrorMaskSafe(dstRect, m_tmpDevice, 0, 0, dab,
                                    !m_dabCache->needSeparateOriginal());

    return effectiveSpacing(scale, rotation);
}
Exemple #23
0
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);

}
Exemple #24
0
qreal KisFilterOp::paintAt(const KisPaintInformation& info)
{
    if (!painter()) {
        return 1.0;
    }

    if (!m_filter) {
        return 1.0;
    }

    if (!source()) {
        return 1.0;
    }

    KisBrushSP brush = m_brush;;
    if (!brush) return 1.0;

    if (! brush->canPaintFor(info))
        return 1.0;

    qreal scale = KisPaintOp::scaleForPressure(m_sizeOption.apply(info));
    if ((scale * brush->width()) <= 0.01 || (scale * brush->height()) <= 0.01) return spacing(scale);

    setCurrentScale(scale);
    
    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;
    qreal xFraction;
    qint32 y;
    qreal yFraction;

    splitCoordinate(pt.x(), &x, &xFraction);
    splitCoordinate(pt.y(), &y, &yFraction);

    qint32 maskWidth = brush->maskWidth(scale, 0.0);
    qint32 maskHeight = brush->maskHeight(scale, 0.0);

    // Filter the paint device
    m_filter->process(KisConstProcessingInformation(source(), QPoint(x, y)),
                    KisProcessingInformation(m_tmpDevice, QPoint(0, 0)),
                    QSize(maskWidth, maskHeight),
                    m_filterConfiguration, 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 (!m_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->opacityU8(itTmpDev.rawData());
                quint8 alphaSrc = cs->opacityU8(itSrc.rawData());

                cs->setOpacity(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 (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return 1.0;

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