inline void setPixel(KisFixedPaintDeviceSP dev, int x, int y, quint8 alpha)
{
    KoColor c(Qt::black, dev->colorSpace());
    c.setOpacity(alpha);

    dev->fill(x, y, 1, 1, c.data());
}
void HairyBrush::fromDabWithDensity(KisFixedPaintDeviceSP dab, qreal density)
{
    int width = dab->bounds().width();
    int height = dab->bounds().height(); 

    int centerX = width * 0.5;
    int centerY = height * 0.5;
   
    // make mask 
    Bristle * bristle = 0;
    qreal alpha;
    
    quint8 * dabPointer = dab->data();
    quint8 pixelSize = dab->pixelSize();
    const KoColorSpace * cs = dab->colorSpace();
    KoColor bristleColor(cs);
    
    srand48(12345678);
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            alpha =  cs->opacityF(dabPointer);
            if (alpha != 0.0){
                if (density == 1.0 || drand48() <= density){
                    memcpy(bristleColor.data(), dabPointer, pixelSize);
                
                    bristle = new Bristle(x - centerX, y - centerY, alpha); // using value from image as length of bristle    
                    bristle->setColor(bristleColor);
                
                    m_bristles.append(bristle);
                }
            } 
            dabPointer += pixelSize;
        }
    }
}
void KisPressureSharpnessOption::applyThreshold(KisFixedPaintDeviceSP dab)
{
    if (!isChecked()) return;
    const KoColorSpace * cs = dab->colorSpace();

    // Set all alpha > opaque/2 to opaque, the rest to transparent.
    // XXX: Using 4/10 as the 1x1 circle brush paints nothing with 0.5.
    quint8* dabPointer = dab->data();
    QRect rc = dab->bounds();

    int pixelSize = dab->pixelSize();
    int pixelCount = rc.width() * rc.height();

    for (int i = 0; i < pixelCount; i++) {
        quint8 alpha = cs->opacityU8(dabPointer);

        if (alpha < (m_threshold * OPACITY_OPAQUE_U8) / 100) {
            cs->setOpacity(dabPointer, OPACITY_TRANSPARENT_U8, 1);
        }
        else {
            cs->setOpacity(dabPointer, OPACITY_OPAQUE_U8, 1);
        }

        dabPointer += pixelSize;
    }
}
inline quint8 pixel(KisFixedPaintDeviceSP dev, int x, int y)
{
    KoColor c(Qt::black, dev->colorSpace());


    dev->readBytes(c.data(), x, y, 1, 1);
    return c.opacityU8();
}
void KisFixedPaintDeviceTest::testColorSpaceConversion()
{
    QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "tile.png");
    const KoColorSpace* srcCs = KoColorSpaceRegistry::instance()->rgb8();
    const KoColorSpace* dstCs = KoColorSpaceRegistry::instance()->lab16();
    KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(srcCs);
    dev->convertFromQImage(image, 0);

    dev->convertTo(dstCs);

    QVERIFY(dev->bounds() == QRect(0, 0, image.width(), image.height()));
    QVERIFY(dev->pixelSize() == dstCs->pixelSize());
    QVERIFY(*dev->colorSpace() == *dstCs);

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

}
QImage KisAutoBrush::createBrushPreview()
{
    srand(0);
    srand48(0);
    int width = maskWidth(1.0, 0.0, 0.0, 0.0, KisPaintInformation());
    int height = maskHeight(1.0, 0.0, 0.0, 0.0, KisPaintInformation());

    KisPaintInformation info(QPointF(width * 0.5, height * 0.5), 0.5, 0, 0, 0, 0);

    KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice( KoColorSpaceRegistry::instance()->rgb8() );
    fdev->setRect(QRect(0, 0, width, height));
    fdev->initialize();

    mask(fdev,KoColor(Qt::black, fdev->colorSpace()),1.0, 1.0, 0.0, info);
    return fdev->convertToQImage(0);
}
void KisFixedPaintDeviceTest::testCreation()
{
    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
    KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(cs);

    dev = new KisFixedPaintDevice(cs);
    QVERIFY(dev->bounds() == QRect());
    QVERIFY(*dev->colorSpace() == *cs);
    QVERIFY(dev->pixelSize() == cs->pixelSize());

    dev->setRect(QRect(0, 0, 100, 100));
    QVERIFY(dev->bounds() == QRect(0, 0, 100, 100));
    dev->initialize();
    QVERIFY(dev->data() != 0);

    quint8* data = dev->data();
    for (uint i = 0; i < 100 * 100 * cs->pixelSize(); ++i) {
        QVERIFY(data[i] == 0);
    }

}
Exemple #9
0
void KisBidirectionalMixingOption::applyFixed(KisFixedPaintDeviceSP dab, KisPaintDeviceSP device, KisPainter* painter, qint32 sx, qint32 sy, qint32 sw, qint32 sh, quint8 pressure, const QRect& dstRect)
{
    if (!isChecked()) return;

    KisFixedPaintDevice canvas(device->colorSpace());
    canvas.setRect(QRect(dstRect.x(), dstRect.y(), sw, sh));
    canvas.initialize();
    device->readBytes(canvas.data(), canvas.bounds());

    const KoColorSpace* cs = dab->colorSpace();
    int channelCount = cs->channelCount();

    quint8* dabPointer = dab->data();
    quint8* canvasPointer = canvas.data();

    QVector<float> cc(channelCount ), dc(channelCount );

    for (int y = 0; y < sh; y++) {
        for (int x = 0; x < sw; x++) {
            if (cs->alpha(dabPointer) > 10 && cs->alpha(canvasPointer) > 10) {

                cs->normalisedChannelsValue(canvasPointer, cc);
                cs->normalisedChannelsValue(dabPointer, dc);

                for (int i = 0; i < channelCount ; i++) {
                    dc[i] = (1.0 - 0.4 * pressure) * cc[i] + 0.4 * pressure * dc[i];
                }

                cs->fromNormalisedChannelsValue(dabPointer, dc);

                if (x == (int)(sw / 2) && y == (int)(sh / 2))
                    painter->setPaintColor(KoColor(dabPointer, cs));
            }
        }
        dabPointer += dab->pixelSize();
        canvasPointer += canvas.pixelSize();
    }

}
void KisAutoBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst,
        KisBrush::ColoringInformation* coloringInformation,
        double scaleX, double scaleY, double angle,
        const KisPaintInformation& info,
        double subPixelX , double subPixelY, qreal softnessFactor) const
{
    Q_UNUSED(info);

    // Generate the paint device from the mask
    const KoColorSpace* cs = dst->colorSpace();
    quint32 pixelSize = cs->pixelSize();

    // mask dimension methods already includes KisBrush::angle()
    int dstWidth = maskWidth(scaleX, angle, subPixelX, subPixelY, info);
    int dstHeight = maskHeight(scaleY, angle, subPixelX, subPixelY, info);
    QPointF hotSpot = this->hotSpot(scaleX, scaleY, angle, info);

    // mask size and hotSpot function take the KisBrush rotation into account
    angle += KisBrush::angle();

    // if there's coloring information, we merely change the alpha: in that case,
    // the dab should be big enough!
    if (coloringInformation) {

        // old bounds
        QRect oldBounds = dst->bounds();

        // new bounds. we don't care if there is some extra memory occcupied.
        dst->setRect(QRect(0, 0, dstWidth, dstHeight));

        if (dstWidth * dstHeight <= oldBounds.width() * oldBounds.height()) {
            // just clear the data in dst,
            memset(dst->data(), OPACITY_TRANSPARENT_U8, dstWidth * dstHeight * dst->pixelSize());
        } else {
            // enlarge the data
            dst->initialize();
        }
    } else {
        if (dst->data() == 0 || dst->bounds().isEmpty()) {
            qWarning() << "Creating a default black dab: no coloring info and no initialized paint device to mask";
            dst->clear(QRect(0, 0, dstWidth, dstHeight));
        }
        Q_ASSERT(dst->bounds().width() >= dstWidth && dst->bounds().height() >= dstHeight);
    }

    quint8* dabPointer = dst->data();

    quint8* color = 0;
    if (coloringInformation) {
        if (dynamic_cast<PlainColoringInformation*>(coloringInformation)) {
            color = const_cast<quint8*>(coloringInformation->color());
        }
    }

    double invScaleX = 1.0 / scaleX;
    double invScaleY = 1.0 / scaleY;

    double centerX = hotSpot.x() - 0.5 + subPixelX;
    double centerY = hotSpot.y() - 0.5 + subPixelY;

    d->shape->setSoftness( softnessFactor );

    if (coloringInformation) {
        if (color && pixelSize == 4) {
            fillPixelOptimized_4bytes(color, dabPointer, dstWidth * dstHeight);
        } else if (color) {
            fillPixelOptimized_general(color, dabPointer, dstWidth * dstHeight, pixelSize);
        } else {
            for (int y = 0; y < dstHeight; y++) {
                for (int x = 0; x < dstWidth; x++) {
                    memcpy(dabPointer, coloringInformation->color(), pixelSize);
                    coloringInformation->nextColumn();
                    dabPointer += pixelSize;
                }
                coloringInformation->nextRow();
            }
        }
    }

    MaskProcessingData data(dst, cs, d->randomness, d->density,
                            centerX, centerY,
                            invScaleX, invScaleY,
                            angle);

    KisBrushMaskApplicatorBase *applicator = d->shape->applicator();
    applicator->initializeData(&data);

    int jobs = d->idealThreadCountCached;
    if(dstHeight > 100 && jobs >= 4) {
        int splitter = dstHeight/jobs;
        QVector<QRect> rects;
        for(int i = 0; i < jobs - 1; i++) {
            rects << QRect(0, i*splitter, dstWidth, splitter);
        }
        rects << QRect(0, (jobs - 1)*splitter, dstWidth, dstHeight - (jobs - 1)*splitter);
        OperatorWrapper wrapper(applicator);
        QtConcurrent::blockingMap(rects, wrapper);
    } else {
        QRect rect(0, 0, dstWidth, dstHeight);
        applicator->process(rect);
    }
}
Exemple #11
0
void KisBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst,
        ColoringInformation* coloringInformation,
        double scaleX, double scaleY, double angle,
        const KisPaintInformation& info_,
        double subPixelX, double subPixelY, qreal softnessFactor) const
{
    Q_ASSERT(valid());
    Q_UNUSED(info_);
    Q_UNUSED(softnessFactor);

    angle += d->angle;

    // Make sure the angle stay in [0;2*M_PI]
    if (angle < 0) angle += 2 * M_PI;
    if (angle > 2 * M_PI) angle -= 2 * M_PI;
    scaleX *= d->scale;
    scaleY *= d->scale;

    double scale = 0.5 * (scaleX + scaleY);

    prepareBrushPyramid();
    QImage outputImage = d->brushPyramid->createImage(scale, -angle, subPixelX, subPixelY);

    qint32 maskWidth = outputImage.width();
    qint32 maskHeight = outputImage.height();

    dst->setRect(QRect(0, 0, maskWidth, maskHeight));
    dst->initialize();

    quint8* color = 0;

    if (coloringInformation) {
        if (dynamic_cast<PlainColoringInformation*>(coloringInformation)) {
            color = const_cast<quint8*>(coloringInformation->color());
        }
    }

    const KoColorSpace *cs = dst->colorSpace();
    qint32 pixelSize = cs->pixelSize();
    quint8 *dabPointer = dst->data();
    quint8 *rowPointer = dabPointer;
    quint8 *alphaArray = new quint8[maskWidth];
    bool hasColor = this->hasColor();

    for (int y = 0; y < maskHeight; y++) {
#if QT_VERSION >= 0x040700
        const quint8* maskPointer = outputImage.constScanLine(y);
#else
        const quint8* maskPointer = outputImage.scanLine(y);
#endif
        if (coloringInformation) {
            for (int x = 0; x < maskWidth; x++) {
                if (color) {
                    memcpy(dabPointer, color, pixelSize);
                }
                else {
                    memcpy(dabPointer, coloringInformation->color(), pixelSize);
                    coloringInformation->nextColumn();
                }
                dabPointer += pixelSize;
            }
        }

        if (hasColor) {
            const quint8 *src = maskPointer;
            quint8 *dst = alphaArray;
            for (int x = 0; x < maskWidth; x++) {
                const QRgb *c = reinterpret_cast<const QRgb*>(src);

                *dst = KoColorSpaceMaths<quint8>::multiply(255 - qGray(*c), qAlpha(*c));
                src += 4;
                dst++;
            }
        }
        else {
            const quint8 *src = maskPointer;
            quint8 *dst = alphaArray;
            for (int x = 0; x < maskWidth; x++) {
                const QRgb *c = reinterpret_cast<const QRgb*>(src);

                *dst = KoColorSpaceMaths<quint8>::multiply(255 - *src, qAlpha(*c));
                src += 4;
                dst++;
            }
        }

        cs->applyAlphaU8Mask(rowPointer, alphaArray, maskWidth);
        rowPointer += maskWidth * pixelSize;
        dabPointer = rowPointer;

        if (!color && coloringInformation) {
            coloringInformation->nextRow();
        }
    }

    delete alphaArray;
}