void KisPerspectiveTransformWorker::runPartialDst(KisPaintDeviceSP srcDev,
                                                  KisPaintDeviceSP dstDev,
                                                  const QRect &dstRect)
{
    if (m_isIdentity) {
        KisPainter::copyAreaOptimizedOldData(dstRect.topLeft(), srcDev, dstDev, dstRect);
        return;
    }

    QRectF srcClipRect = srcDev->exactBounds();
    if (srcClipRect.isEmpty()) return;

    KisProgressUpdateHelper progressHelper(m_progressUpdater, 100, dstRect.height());

    KisRandomSubAccessorSP srcAcc = srcDev->createRandomSubAccessor();
    KisRandomAccessorSP accessor = dstDev->createRandomAccessorNG(dstRect.x(), dstRect.y());

    for (int y = dstRect.y(); y < dstRect.y() + dstRect.height(); ++y) {
        for (int x = dstRect.x(); x < dstRect.x() + dstRect.width(); ++x) {

            QPointF dstPoint(x, y);
            QPointF srcPoint = m_backwardTransform.map(dstPoint);

            if (srcClipRect.contains(srcPoint)) {
                accessor->moveTo(dstPoint.x(), dstPoint.y());
                srcAcc->moveTo(srcPoint.x(), srcPoint.y());
                srcAcc->sampledOldRawData(accessor->rawData());
            }
        }
        progressHelper.step();
    }

}
Esempio n. 2
0
KisScanlineFill::KisScanlineFill(KisPaintDeviceSP device, const QPoint &startPoint, const QRect &boundingRect)
    : m_d(new Private)
{
    m_d->device = device;
    m_d->it = device->createRandomAccessorNG(startPoint.x(), startPoint.y());
    m_d->startPoint = startPoint;
    m_d->boundingRect = boundingRect;

    m_d->rowIncrement = 1;

    m_d->threshold = 0;
}
Esempio n. 3
0
void ChalkBrush::paint(KisPaintDeviceSP dev, qreal x, qreal y, const KoColor &color, qreal additionalScale)
{
    m_inkColor = color;
    m_counter++;

    qint32 pixelSize = dev->colorSpace()->pixelSize();
    KisRandomAccessorSP accessor = dev->createRandomAccessorNG((int)x, (int)y);

    qreal result;
    if (m_properties->inkDepletion) {
        //count decrementing of saturation and opacity
        result = log((qreal)m_counter);
        result = -(result * 10) / 100.0;

        if (m_properties->useSaturation) {
            if (m_transfo) {
                m_transfo->setParameter(m_saturationId, 1.0f + result);
                m_transfo->transform(m_inkColor.data(), m_inkColor.data(), 1);
            }

        }

        if (m_properties->useOpacity) {
            qreal opacity = (1.0f + result);
            m_inkColor.setOpacity(opacity);
        }
    }

    int pixelX, pixelY;
    const int radius = m_properties->radius * additionalScale;
    const int radiusSquared = pow2(radius);
    double dirtThreshold = 0.5;


    for (int by = -radius; by <= radius; by++) {
        int bySquared = by * by;
        for (int bx = -radius; bx <= radius; bx++) {
            // let's call that noise from ground to chalk :)
            if (((bx * bx + bySquared) > radiusSquared) ||
                m_randomSource.generateNormalized() < dirtThreshold) {
                continue;
            }

            pixelX = qRound(x + bx);
            pixelY = qRound(y + by);

            accessor->moveTo(pixelX, pixelY);
            memcpy(accessor->rawData(), m_inkColor.data(), pixelSize);
        }
    }
}
Esempio n. 4
0
void testWrappedLineIteratorReadMoreThanBounds(QString testName)
{
    const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
    KisPaintDeviceSP dev = createWrapAroundPaintDevice(cs);
    KisPaintDeviceSP dst = new KisPaintDevice(cs);

    // fill device with a gradient
    QRect bounds = dev->defaultBounds()->bounds();
    for (int y = bounds.y(); y < bounds.y() + bounds.height(); y++) {
        for (int x = bounds.x(); x < bounds.x() + bounds.width(); x++) {
            QColor c((10 * x) % 255, (10 * y) % 255, 0, 255);
            dev->setPixel(x, y, c);
        }
    }

    // test rect doesn't fit the wrap rect in both dimentions
    const QRect &rect(bounds.adjusted(-6,-6,8,8));
    KisRandomAccessorSP dstIt = dst->createRandomAccessorNG(rect.x(), rect.y());
    IteratorSP it = createIterator<IteratorSP>(dev, rect);

    for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
        for (int x = rect.x(); x < rect.x() + rect.width(); x++) {
            quint8 *data = it->rawData();

            QVERIFY(checkConseqPixels<IteratorSP>(it->nConseqPixels(), QPoint(x, y), KisWrappedRect(rect, bounds)));

            dstIt->moveTo(x, y);
            memcpy(dstIt->rawData(), data, cs->pixelSize());

            QVERIFY(checkXY<IteratorSP>(QPoint(it->x(), it->y()), QPoint(x,y)));

            bool stepDone = it->nextPixel();
            QCOMPARE(stepDone, x < rect.x() + rect.width() - 1);
        }
        if (!nextRowGeneral(it, y, rect)) break;
    }

    testName = QString("%1_%2_%3_%4_%5")
        .arg(testName)
        .arg(rect.x())
        .arg(rect.y())
        .arg(rect.width())
        .arg(rect.height());

    QRect rc = rect;
    QImage result = dst->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height());
    QImage ref = dev->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height());

    QVERIFY(TestUtil::checkQImage(result, "paint_device_test", "wrapped_iterators_huge", testName));
}
Esempio n. 5
0
/* Function to apply the Emboss effect
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * d                => Emboss value
 *
 * Theory           => This is an amazing effect. And the theory is very simple to
 *                     understand. You get the diference between the colors and
 *                     increase it. After this, get the gray tone
 */
void KisEmbossFilter::processImpl(KisPaintDeviceSP device,
                                  const QRect& applyRect,
                                  const KisFilterConfigurationSP config,
                                  KoUpdater* progressUpdater
                                  ) const
{
    QPoint srcTopLeft = applyRect.topLeft();
    Q_ASSERT(device);

    //read the filter configuration values from the KisFilterConfiguration object
    quint32 embossdepth = config ?  config->getInt("depth", 30) : 30;

    //the actual filter function from digikam. It needs a pointer to a quint8 array
    //with the actual pixel data.

    float Depth = embossdepth / 10.0;
    int    R = 0, G = 0, B = 0;
    uchar  Gray = 0;
    int Width = applyRect.width();
    int Height = applyRect.height();

    if (progressUpdater) {
        progressUpdater->setRange(0, Height);
    }

    KisSequentialIterator it(device, applyRect);
    QColor color1;
    QColor color2;
    KisRandomConstAccessorSP acc = device->createRandomAccessorNG(srcTopLeft.x(), srcTopLeft.y());
    do {
    
        // XXX: COLORSPACE_INDEPENDENCE or at least work IN RGB16A
        device->colorSpace()->toQColor(it.oldRawData(), &color1);
        acc->moveTo(srcTopLeft.x() + it.x() + Lim_Max(it.x(), 1, Width), srcTopLeft.y() + it.y() + Lim_Max(it.y(), 1, Height));

        device->colorSpace()->toQColor(acc->oldRawData(), &color2);

        R = abs((int)((color1.red() - color2.red()) * Depth + (quint8_MAX / 2)));
        G = abs((int)((color1.green() - color2.green()) * Depth + (quint8_MAX / 2)));
        B = abs((int)((color1.blue() - color2.blue()) * Depth + (quint8_MAX / 2)));

        Gray = CLAMP((R + G + B) / 3, 0, quint8_MAX);

        device->colorSpace()->fromQColor(QColor(Gray, Gray, Gray, color1.alpha()), it.rawData());
        if (progressUpdater) { progressUpdater->setValue(it.y()); if(progressUpdater->interrupted()) return; }
    } while(it.nextPixel());
}
Esempio n. 6
0
void SprayBrush::paint(KisPaintDeviceSP dab, KisPaintDeviceSP source,
                       const KisPaintInformation& info, qreal rotation, qreal scale,
                       const KoColor &color, const KoColor &bgColor)
{
    // initializing painter
    if (!m_painter) {
        m_painter = new KisPainter(dab);
        m_painter->setFillStyle(KisPainter::FillStyleForegroundColor);
        m_painter->setMaskImageSize(m_shapeProperties->width, m_shapeProperties->height);
        m_dabPixelSize = dab->colorSpace()->pixelSize();
        if (m_colorProperties->useRandomHSV) {
            m_transfo = dab->colorSpace()->createColorTransformation("hsv_adjustment", QHash<QString, QVariant>());
        }

        m_brushQImage = m_shapeProperties->image;
        if (!m_brushQImage.isNull()) {
            m_brushQImage = m_brushQImage.scaled(m_shapeProperties->width, m_shapeProperties->height);
        }
        m_imageDevice = new KisPaintDevice(dab->colorSpace());
    }


    qreal x = info.pos().x();
    qreal y = info.pos().y();
    KisRandomAccessorSP accessor = dab->createRandomAccessorNG(qRound(x), qRound(y));

    Q_ASSERT(color.colorSpace()->pixelSize() == dab->pixelSize());
    m_inkColor = color;
    KisCrossDeviceColorPicker colorPicker(source, m_inkColor);

    // apply size sensor
    m_radius = m_properties->radius * scale;

    // jitter movement
    if (m_properties->jitterMovement) {
        x = x + ((2 * m_radius * drand48()) - m_radius) * m_properties->amount;
        y = y + ((2 * m_radius * drand48()) - m_radius) * m_properties->amount;
    }

    // this is wrong for every shape except pixel and anti-aliased pixel


    if (m_properties->useDensity) {
        m_particlesCount = (m_properties->coverage * (M_PI * m_radius * m_radius));
    }
    else {
        m_particlesCount = m_properties->particleCount;
    }

    QHash<QString, QVariant> params;
    qreal nx, ny;
    int ix, iy;

    qreal angle;
    qreal length;
    qreal rotationZ = 0.0;
    qreal particleScale = 1.0;

    bool shouldColor = true;
    if (m_colorProperties->fillBackground) {
        m_painter->setPaintColor(bgColor);
        paintCircle(m_painter, x, y, m_radius);
    }

    QTransform m;
    m.reset();
    m.rotateRadians(-rotation + deg2rad(m_properties->brushRotation));
    m.scale(m_properties->scale, m_properties->scale);

    for (quint32 i = 0; i < m_particlesCount; i++) {
        // generate random angle
        angle = drand48() * M_PI * 2;

        // generate random length
        if (m_properties->gaussian) {
            length = qBound<qreal>(0.0, m_rand->nextGaussian(0.0, 0.50) , 1.0);
        }
        else {
            length = drand48();
        }

        if (m_shapeDynamicsProperties->enabled) {
            // rotation
            rotationZ = rotationAngle();

            if (m_shapeDynamicsProperties->followCursor) {

                rotationZ = linearInterpolation(rotationZ, angle, m_shapeDynamicsProperties->followCursorWeigth);
            }


            if (m_shapeDynamicsProperties->followDrawingAngle) {

                rotationZ = linearInterpolation(rotationZ, info.drawingAngle(), m_shapeDynamicsProperties->followDrawingAngleWeight);
            }

            // random size - scale
            if (m_shapeDynamicsProperties->randomSize) {
                particleScale = drand48();
            }
        }
        // generate polar coordinate
        nx = (m_radius * cos(angle)  * length);
        ny = (m_radius * sin(angle)  * length);

        // compute the height of the ellipse
        ny *= m_properties->aspect;

        // transform
        m.map(nx, ny, &nx, &ny);

        // color transformation

        if (shouldColor) {
            if (m_colorProperties->sampleInputColor) {
                colorPicker.pickOldColor(nx + x, ny + y, m_inkColor.data());
            }

            // mix the color with background color
            if (m_colorProperties->mixBgColor) {
                KoMixColorsOp * mixOp = dab->colorSpace()->mixColorsOp();

                const quint8 *colors[2];
                colors[0] = m_inkColor.data();
                colors[1] = bgColor.data();

                qint16 colorWeights[2];
                int MAX_16BIT = 255;
                qreal blend = info.pressure();

                colorWeights[0] = static_cast<quint16>(blend * MAX_16BIT);
                colorWeights[1] = static_cast<quint16>((1.0 - blend) * MAX_16BIT);
                mixOp->mixColors(colors, colorWeights, 2, m_inkColor.data());
            }

            if (m_colorProperties->useRandomHSV && m_transfo) {
                params["h"] = (m_colorProperties->hue / 180.0) * drand48();
                params["s"] = (m_colorProperties->saturation / 100.0) * drand48();
                params["v"] = (m_colorProperties->value / 100.0) * drand48();
                m_transfo->setParameters(params);
                m_transfo->transform(m_inkColor.data(), m_inkColor.data() , 1);
            }

            if (m_colorProperties->useRandomOpacity) {
                quint8 alpha = qRound(drand48() * OPACITY_OPAQUE_U8);
                m_inkColor.setOpacity(alpha);
                m_painter->setOpacity(alpha);
            }

            if (!m_colorProperties->colorPerParticle) {
                shouldColor = false;
            }
            m_painter->setPaintColor(m_inkColor);
        }

        qreal jitteredWidth = qMax(qreal(1.0), m_shapeProperties->width * particleScale);
        qreal jitteredHeight = qMax(qreal(1.0), m_shapeProperties->height * particleScale);

        if (m_shapeProperties->enabled){
        switch (m_shapeProperties->shape){
            // ellipse
            case 0:
            {
                if (m_shapeProperties->width == m_shapeProperties->height){
                    paintCircle(m_painter, nx + x, ny + y, qRound(jitteredWidth * 0.5));
                }
                else {
                    paintEllipse(m_painter, nx + x, ny + y, qRound(jitteredWidth * 0.5) , qRound(jitteredHeight * 0.5), rotationZ);
                }
                break;
            }
            // rectangle
            case 1:
            {
                paintRectangle(m_painter, nx + x, ny + y, qRound(jitteredWidth) , qRound(jitteredHeight), rotationZ);
                break;
            }
            // wu-particle
            case 2: {
                paintParticle(accessor, m_inkColor, nx + x, ny + y);
                break;
            }
            // pixel
            case 3: {
                ix = qRound(nx + x);
                iy = qRound(ny + y);
                accessor->moveTo(ix, iy);
                memcpy(accessor->rawData(), m_inkColor.data(), m_dabPixelSize);
                break;
            }
            case 4: {
                if (!m_brushQImage.isNull()) {

                    QTransform m;
                    m.rotate(rad2deg(rotationZ));

                    if (m_shapeDynamicsProperties->randomSize) {
                        m.scale(particleScale, particleScale);
                    }
                    m_transformed = m_brushQImage.transformed(m, Qt::SmoothTransformation);
                    m_imageDevice->convertFromQImage(m_transformed, 0);
                    KisRandomAccessorSP ac = m_imageDevice->createRandomAccessorNG(0, 0);
                    QRect rc = m_transformed.rect();

                    if (m_colorProperties->useRandomHSV && m_transfo) {

                        for (int y = rc.y(); y < rc.y() + rc.height(); y++) {
                            for (int x = rc.x(); x < rc.x() + rc.width(); x++) {
                                ac->moveTo(x, y);
                                m_transfo->transform(ac->rawData(), ac->rawData() , 1);
                            }
                        }
                    }

                    ix = qRound(nx + x - rc.width() * 0.5);
                    iy = qRound(ny + y - rc.height() * 0.5);
                    m_painter->bitBlt(QPoint(ix, iy), m_imageDevice, rc);
                    m_imageDevice->clear();
                    break;
                }
            }
            }
            // Auto-brush
        }
        else {
            QPointF hotSpot = m_brush->hotSpot(particleScale, particleScale, -rotationZ, info);
            QPointF pos(nx + x, ny + y);
            QPointF pt = pos - hotSpot;

            qint32 ix;
            qreal xFraction;
            qint32 iy;
            qreal yFraction;

            KisPaintOp::splitCoordinate(pt.x(), &ix, &xFraction);
            KisPaintOp::splitCoordinate(pt.y(), &iy, &yFraction);

            //KisFixedPaintDeviceSP dab;
            if (m_brush->brushType() == IMAGE ||
                    m_brush->brushType() == PIPE_IMAGE) {
                m_fixedDab = m_brush->paintDevice(m_fixedDab->colorSpace(), particleScale, -rotationZ, info, xFraction, yFraction);

                if (m_colorProperties->useRandomHSV && m_transfo) {
                    quint8 * dabPointer = m_fixedDab->data();
                    int pixelCount = m_fixedDab->bounds().width() * m_fixedDab->bounds().height();
                    m_transfo->transform(dabPointer, dabPointer, pixelCount);
                }

            }
            else {
                m_brush->mask(m_fixedDab, m_inkColor, particleScale, particleScale, -rotationZ, info, xFraction, yFraction);
            }
            m_painter->bltFixed(QPoint(ix, iy), m_fixedDab, m_fixedDab->bounds());
        }
    }
    // recover from jittering of color,
    // m_inkColor.opacity is recovered with every paint
}
Esempio n. 7
0
void SprayBrush::paintOutline(KisPaintDeviceSP dev , const KoColor &outlineColor, qreal posX, qreal posY, qreal radius)
{
    QList<QPointF> antiPixels;
    KisRandomAccessorSP accessor = dev->createRandomAccessorNG(qRound(posX), qRound(posY));

    for (int y = -radius + posY; y <= radius + posY; y++) {
        for (int x = -radius + posX; x <= radius + posX; x++) {
            accessor->moveTo(x, y);
            qreal alpha = dev->colorSpace()->opacityU8(accessor->rawData());

            if (alpha != 0) {
                // top left
                accessor->moveTo(x - 1, y - 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x - 1, y - 1));
                    //continue;
                }

                // top
                accessor->moveTo(x, y - 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x, y - 1));
                    //continue;
                }

                // top right
                accessor->moveTo(x + 1, y - 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x + 1, y - 1));
                    //continue;
                }

                //left
                accessor->moveTo(x - 1, y);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x - 1, y));
                    //continue;
                }

                //right
                accessor->moveTo(x + 1, y);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x + 1, y));
                    //continue;
                }

                // bottom left
                accessor->moveTo(x - 1, y + 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x - 1, y + 1));
                    //continue;
                }

                // bottom
                accessor->moveTo(x, y + 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x, y + 1));
                    //continue;
                }

                // bottom right
                accessor->moveTo(x + 1, y + 1);
                if (dev->colorSpace()->opacityU8(accessor->rawData()) == 0) {
                    antiPixels.append(QPointF(x + 1, y + 1));
                    //continue;
                }
            }

        }
    }

    // anti-alias it
    int size = antiPixels.size();
    for (int i = 0; i < size; i++) {
        accessor->moveTo(antiPixels[i].x(), antiPixels[i].y());
        memcpy(accessor->rawData(), outlineColor.data(), dev->colorSpace()->pixelSize());
    }
}
Esempio n. 8
0
void KisGmicSimpleConvertor::convertFromGmicImage(gmic_image<float>& gmicImage, KisPaintDeviceSP dst, float gmicMaxChannelValue)
{
    Q_ASSERT(!dst.isNull());
    const KoColorSpace *rgbaFloat32bitcolorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
                                                                                                Float32BitsColorDepthID.id(),
                                                                                                KoColorSpaceRegistry::instance()->rgb8()->profile());
    const KoColorSpace *dstColorSpace = dst->colorSpace();
    if (dstColorSpace == 0)
    {
        dstColorSpace = rgbaFloat32bitcolorSpace;
    }

    KisPaintDeviceSP dev = dst;
    int greenOffset = gmicImage._width * gmicImage._height;
    int blueOffset = greenOffset * 2;
    int alphaOffset = greenOffset * 3;
    QRect rc(0,0,gmicImage._width, gmicImage._height);

    KisRandomAccessorSP it = dev->createRandomAccessorNG(0,0);
    int pos;
    float r,g,b,a;

    int optimalBufferSize = 64; // most common numContiguousColumns, tile size?
    quint8 * floatRGBApixel = new quint8[rgbaFloat32bitcolorSpace->pixelSize() * optimalBufferSize];
    quint32 pixelSize = rgbaFloat32bitcolorSpace->pixelSize();

    KoColorConversionTransformation::Intent renderingIntent = KoColorConversionTransformation::internalRenderingIntent();
    KoColorConversionTransformation::ConversionFlags conversionFlags = KoColorConversionTransformation::internalConversionFlags();

    // Krita needs rgba in 0.0...1.0
    float multiplied = KoColorSpaceMathsTraits<float>::unitValue / gmicMaxChannelValue;

    switch (gmicImage._spectrum)
    {
        case 1:
        {
            // convert grayscale to rgba
            for (int y = 0; y < rc.height(); y++)
            {
                int x = 0;
                while (x < rc.width())
                {
                    it->moveTo(x, y);
                    qint32 numContiguousColumns = qMin(it->numContiguousColumns(x), optimalBufferSize);
                    numContiguousColumns = qMin(numContiguousColumns, rc.width() - x);

                    pos = y * gmicImage._width + x;
                    for (qint32 bx = 0; bx < numContiguousColumns; bx++)
                    {
                            r = g = b = gmicImage._data[pos] * multiplied;
                            a = KoColorSpaceMathsTraits<float>::unitValue;

                            memcpy(floatRGBApixel + bx * pixelSize,      &r,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 4,  &g,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 8,  &b,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 12, &a,4);
                            pos++;
                    }
                    rgbaFloat32bitcolorSpace->convertPixelsTo(floatRGBApixel, it->rawData(), dstColorSpace, numContiguousColumns,renderingIntent, conversionFlags);
                    x += numContiguousColumns;
                }
            }
            break;
        }
        case 2:
        {
            // convert grayscale alpha to rgba
            for (int y = 0; y < rc.height(); y++)
            {
                int x = 0;
                while (x < rc.width())
                {
                    it->moveTo(x, y);
                    qint32 numContiguousColumns = qMin(it->numContiguousColumns(x), optimalBufferSize);
                    numContiguousColumns = qMin(numContiguousColumns, rc.width() - x);

                    pos = y * gmicImage._width + x;
                    for (qint32 bx = 0; bx < numContiguousColumns; bx++)
                    {
                            r = g = b = gmicImage._data[pos] * multiplied;
                            a = gmicImage._data[pos + greenOffset] * multiplied;

                            memcpy(floatRGBApixel + bx * pixelSize,      &r,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 4,  &g,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 8,  &b,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 12, &a,4);
                            pos++;
                    }
                    rgbaFloat32bitcolorSpace->convertPixelsTo(floatRGBApixel, it->rawData(), dstColorSpace, numContiguousColumns,renderingIntent, conversionFlags);
                    x += numContiguousColumns;
                }
            }
            break;
        }
        case 3:
        {
            // convert rgb -> rgba
            for (int y = 0; y < rc.height(); y++)
            {
                int x = 0;
                while (x < rc.width())
                {
                    it->moveTo(x, y);
                    qint32 numContiguousColumns = qMin(it->numContiguousColumns(x), optimalBufferSize);
                    numContiguousColumns = qMin(numContiguousColumns, rc.width() - x);

                    pos = y * gmicImage._width + x;
                    for (qint32 bx = 0; bx < numContiguousColumns; bx++)
                    {
                            r = gmicImage._data[pos] * multiplied;
                            g = gmicImage._data[pos + greenOffset] * multiplied;
                            b = gmicImage._data[pos + blueOffset ] * multiplied;
                            a = gmicMaxChannelValue * multiplied;

                            memcpy(floatRGBApixel + bx * pixelSize,      &r,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 4,  &g,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 8,  &b,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 12, &a,4);
                            pos++;
                    }
                    rgbaFloat32bitcolorSpace->convertPixelsTo(floatRGBApixel, it->rawData(), dstColorSpace, numContiguousColumns,renderingIntent, conversionFlags);
                    x += numContiguousColumns;
                }
            }
            break;
        }
        case 4:
        {
            for (int y = 0; y < rc.height(); y++)
            {
                int x = 0;
                while (x < rc.width())
                {
                    it->moveTo(x, y);
                    qint32 numContiguousColumns = qMin(it->numContiguousColumns(x), optimalBufferSize);
                    numContiguousColumns = qMin(numContiguousColumns, rc.width() - x);

                    pos = y * gmicImage._width + x;
                    for (qint32 bx = 0; bx < numContiguousColumns; bx++)
                    {
                            r = gmicImage._data[pos] * multiplied;
                            g = gmicImage._data[pos + greenOffset] * multiplied;
                            b = gmicImage._data[pos + blueOffset ] * multiplied;
                            a = gmicImage._data[pos + alphaOffset] * multiplied;

                            memcpy(floatRGBApixel + bx * pixelSize,      &r,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 4,  &g,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 8,  &b,4);
                            memcpy(floatRGBApixel + bx * pixelSize + 12, &a,4);
                            pos++;
                    }
                    rgbaFloat32bitcolorSpace->convertPixelsTo(floatRGBApixel, it->rawData(), dstColorSpace, numContiguousColumns,renderingIntent, conversionFlags);
                    x += numContiguousColumns;
                }
            }
            break;
        }

        default:
        {
            dbgPlugins << "Unsupported gmic output format : " <<  gmicImage._width << gmicImage._height << gmicImage._depth << gmicImage._spectrum;
        }
    }
}
Esempio n. 9
0
void KisGmicSimpleConvertor::convertFromGmicFast(gmic_image<float>& gmicImage, KisPaintDeviceSP dst, float gmicUnitValue)
{
    const KoColorSpace * dstColorSpace = dst->colorSpace();
    KoColorTransformation * gmicToDstPixelFormat = createTransformationFromGmic(dstColorSpace,gmicImage._spectrum,gmicUnitValue);
    if (gmicToDstPixelFormat == 0)
    {
            dbgPlugins << "Fall-back to slow color conversion";
            convertFromGmicImage(gmicImage, dst, gmicUnitValue);
            return;
    }

    qint32 x = 0;
    qint32 y = 0;
    qint32 width = gmicImage._width;
    qint32 height = gmicImage._height;

    width  = width < 0  ? 0 : width;
    height = height < 0 ? 0 : height;


    const KoColorSpace *rgbaFloat32bitcolorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
                                                                                                Float32BitsColorDepthID.id(),
                                                                                                KoColorSpaceRegistry::instance()->rgb8()->profile());
    // this function always convert to rgba or rgb with various color depth
    quint32 dstNumChannels = rgbaFloat32bitcolorSpace->channelCount();
    // number of channels that we will copy
    quint32 numChannels = gmicImage._spectrum;

    // gmic image has 4, 3, 2, 1 channel
    QVector<float *> planes(dstNumChannels);
    int channelOffset = gmicImage._width * gmicImage._height;
    for (unsigned int channelIndex = 0; channelIndex < gmicImage._spectrum; channelIndex++)
    {
        planes[channelIndex] = gmicImage._data + channelOffset * channelIndex;
    }

    for (unsigned int channelIndex = gmicImage._spectrum; channelIndex < dstNumChannels; channelIndex++)
    {
        planes[channelIndex] = 0; //turn off
    }

    qint32 dataY = 0;
    qint32 imageY = y;
    qint32 rowsRemaining = height;

    const qint32 floatPixelSize = rgbaFloat32bitcolorSpace->pixelSize();

    KisRandomAccessorSP it = dst->createRandomAccessorNG(dst->x(), dst->y()); // 0,0
    int tileWidth = it->numContiguousColumns(dst->x());
    int tileHeight = it->numContiguousRows(dst->y());
    Q_ASSERT(tileWidth == 64);
    Q_ASSERT(tileHeight == 64);
    quint8 * convertedTile = new quint8[rgbaFloat32bitcolorSpace->pixelSize() * tileWidth * tileHeight];

    // grayscale and rgb case does not have alpha, so let's fill 4th channel of rgba tile with opacity opaque
    if (gmicImage._spectrum == 1 || gmicImage._spectrum == 3)
    {
        quint32 nPixels = tileWidth * tileHeight;
        quint32 pixelIndex = 0;
        KoRgbF32Traits::Pixel* srcPixel = reinterpret_cast<KoRgbF32Traits::Pixel*>(convertedTile);
        while (pixelIndex < nPixels)
        {
            srcPixel->alpha = gmicUnitValue;
            ++srcPixel;
            ++pixelIndex;
        }
    }

    while (rowsRemaining > 0) {

        qint32 dataX = 0;
        qint32 imageX = x;
        qint32 columnsRemaining = width;
        qint32 numContiguousImageRows = it->numContiguousRows(imageY);

        qint32 rowsToWork = qMin(numContiguousImageRows, rowsRemaining);

        while (columnsRemaining > 0) {

            qint32 numContiguousImageColumns = it->numContiguousColumns(imageX);
            qint32 columnsToWork = qMin(numContiguousImageColumns, columnsRemaining);

            const qint32 dataIdx = dataX + dataY * width;
            const qint32 tileRowStride = (tileWidth - columnsToWork) * floatPixelSize;

            quint8 *tileItStart = convertedTile;
            // copy gmic channels to float tile
            qint32 channelSize = sizeof(float);
            for(quint32 i=0; i<numChannels; i++)
            {
                float * planeIt = planes[i] + dataIdx;
                qint32 dataStride = (width - columnsToWork);
                quint8* tileIt = tileItStart;

                for (qint32 row = 0; row < rowsToWork; row++) {
                    for (int col = 0; col < columnsToWork; col++) {
                        memcpy(tileIt, planeIt, channelSize);
                        tileIt += floatPixelSize;
                        planeIt += 1;
                    }

                    tileIt += tileRowStride;
                    planeIt += dataStride;
                }
                tileItStart += channelSize;
            }

            it->moveTo(imageX, imageY);
            quint8 *dstTileItStart = it->rawData();
            tileItStart = convertedTile;  // back to the start of the converted tile
            // copy float tile to dst colorspace based on input colorspace (rgb or grayscale)
            for (qint32 row = 0; row < rowsToWork; row++)
            {
                gmicToDstPixelFormat->transform(tileItStart, dstTileItStart, columnsToWork);
                dstTileItStart += dstColorSpace->pixelSize() * tileWidth;
                tileItStart += floatPixelSize * tileWidth;
            }

            imageX += columnsToWork;
            dataX += columnsToWork;
            columnsRemaining -= columnsToWork;
        }


        imageY += rowsToWork;
        dataY += rowsToWork;
        rowsRemaining -= rowsToWork;
    }

    delete [] convertedTile;
    delete gmicToDstPixelFormat;

}
Esempio n. 10
0
 SourceAccessorType createSourceDeviceAccessor(KisPaintDeviceSP device) {
     return device->createRandomAccessorNG(0, 0);
 }
void KisRainDropsFilter::process(KisConstProcessingInformation srcInfo,
                                 KisProcessingInformation dstInfo,
                                 const QSize& size,
                                 const KisFilterConfiguration* config,
                                 KoUpdater* progressUpdater
                                ) const
{

    const KisPaintDeviceSP src = srcInfo.paintDevice();
    KisPaintDeviceSP dst = dstInfo.paintDevice();
    QPoint dstTopLeft = dstInfo.topLeft();
    QPoint srcTopLeft = srcInfo.topLeft();
    Q_UNUSED(config);
    Q_ASSERT(!src.isNull());
    Q_ASSERT(!dst.isNull());

    //read the filter configuration values from the KisFilterConfiguration object
    quint32 DropSize = config->getInt("dropSize", 80);
    quint32 number = config->getInt("number", 80);
    quint32 fishEyes = config->getInt("fishEyes", 30);

    if (progressUpdater) {
        progressUpdater->setRange(0, size.width() * size.height());
    }
    int count = 0;

    if (fishEyes <= 0) fishEyes = 1;

    if (fishEyes > 100) fishEyes = 100;

    int Width = size.width();
    int Height = size.height();

    bool** BoolMatrix = CreateBoolArray(Width, Height);

    int       i, j, k, l, m, n;                 // loop variables
    int       Bright;                           // Bright value for shadows and highlights
    int       x, y;                             // center coordinates
    int       Counter = 0;                      // Counter (duh !)
    int       NewSize;                          // Size of current raindrop
    int       halfSize;                         // Half of the current raindrop
    int       Radius;                           // Maximum radius for raindrop
    int       BlurRadius;                       // Blur Radius
    int       BlurPixels;

    double    r, a;                             // polar coordinates
    double    OldRadius;                        // Radius before processing
    double    NewfishEyes = (double)fishEyes * 0.01;  // FishEye fishEyesicients
    double    s;
    double    R, G, B;

    bool      FindAnother = false;              // To search for good coordinates

    const KoColorSpace * cs = src->colorSpace();


    // XXX: move the seed to the config, so the filter can be used as
    // and adjustment filter (boud).
    // And use a thread-safe random number generator
    QDateTime dt = QDateTime::currentDateTime();
    QDateTime Y2000(QDate(2000, 1, 1), QTime(0, 0, 0));

    srand((uint) dt.secsTo(Y2000));

    // Init booleen Matrix.

    for (i = 0 ; (i < Width) && !(progressUpdater && progressUpdater->interrupted()) ; ++i) {
        for (j = 0 ; (j < Height) && !(progressUpdater && progressUpdater->interrupted()); ++j) {
            BoolMatrix[i][j] = false;
        }
    }

    KisRandomAccessorSP dstAccessor = dst->createRandomAccessorNG(dstTopLeft.x(), dstTopLeft.y());
    KisRandomConstAccessorSP srcAccessor = src->createRandomConstAccessorNG(dstTopLeft.x(), dstTopLeft.y());
    
    for (uint NumBlurs = 0; (NumBlurs <= number) && !(progressUpdater && progressUpdater->interrupted()); ++NumBlurs) {
        NewSize = (int)(rand() * ((double)(DropSize - 5) / RAND_MAX) + 5);
        halfSize = NewSize / 2;
        Radius = halfSize;
        s = Radius / log(NewfishEyes * Radius + 1);

        Counter = 0;

        do {
            FindAnother = false;
            y = (int)(rand() * ((double)(Width - 1) / RAND_MAX));
            x = (int)(rand() * ((double)(Height - 1) / RAND_MAX));

            if (BoolMatrix[y][x])
                FindAnother = true;
            else
                for (i = x - halfSize ; (i <= x + halfSize) && !(progressUpdater && progressUpdater->interrupted()); i++)
                    for (j = y - halfSize ; (j <= y + halfSize) && !(progressUpdater && progressUpdater->interrupted()); j++)
                        if ((i >= 0) && (i < Height) && (j >= 0) && (j < Width))
                            if (BoolMatrix[j][i])
                                FindAnother = true;

            Counter++;
        } while ((FindAnother && (Counter < 10000) && !(progressUpdater && progressUpdater->interrupted())));

        if (Counter >= 10000) {
            NumBlurs = number;
            break;
        }

        for (i = -1 * halfSize ; (i < NewSize - halfSize) && !(progressUpdater && progressUpdater->interrupted()); i++) {
            for (j = -1 * halfSize ; (j < NewSize - halfSize) && !(progressUpdater && progressUpdater->interrupted()); j++) {
                r = sqrt(i * i + j * j);
                a = atan2(static_cast<double>(i), static_cast<double>(j));

                if (r <= Radius) {
                    OldRadius = r;
                    r = (exp(r / s) - 1) / NewfishEyes;

                    k = x + (int)(r * sin(a));
                    l = y + (int)(r * cos(a));

                    m = x + i;
                    n = y + j;

                    if ((k >= 0) && (k < Height) && (l >= 0) && (l < Width)) {
                        if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) {
                            Bright = 0;

                            if (OldRadius >= 0.9 * Radius) {
                                if ((a <= 0) && (a > -2.25))
                                    Bright = -80;
                                else if ((a <= -2.25) && (a > -2.5))
                                    Bright = -40;
                                else if ((a <= 0.25) && (a > 0))
                                    Bright = -40;
                            }

                            else if (OldRadius >= 0.8 * Radius) {
                                if ((a <= -0.75) && (a > -1.50))
                                    Bright = -40;
                                else if ((a <= 0.10) && (a > -0.75))
                                    Bright = -30;
                                else if ((a <= -1.50) && (a > -2.35))
                                    Bright = -30;
                            }

                            else if (OldRadius >= 0.7 * Radius) {
                                if ((a <= -0.10) && (a > -2.0))
                                    Bright = -20;
                                else if ((a <= 2.50) && (a > 1.90))
                                    Bright = 60;
                            }

                            else if (OldRadius >= 0.6 * Radius) {
                                if ((a <= -0.50) && (a > -1.75))
                                    Bright = -20;
                                else if ((a <= 0) && (a > -0.25))
                                    Bright = 20;
                                else if ((a <= -2.0) && (a > -2.25))
                                    Bright = 20;
                            }

                            else if (OldRadius >= 0.5 * Radius) {
                                if ((a <= -0.25) && (a > -0.50))
                                    Bright = 30;
                                else if ((a <= -1.75) && (a > -2.0))
                                    Bright = 30;
                            }

                            else if (OldRadius >= 0.4 * Radius) {
                                if ((a <= -0.5) && (a > -1.75))
                                    Bright = 40;
                            }

                            else if (OldRadius >= 0.3 * Radius) {
                                if ((a <= 0) && (a > -2.25))
                                    Bright = 30;
                            }

                            else if (OldRadius >= 0.2 * Radius) {
                                if ((a <= -0.5) && (a > -1.75))
                                    Bright = 20;
                            }

                            BoolMatrix[n][m] = true;

                            QColor originalColor;

                            srcAccessor->moveTo(srcTopLeft.x() + l, srcTopLeft.y() + k);
                            cs->toQColor(srcAccessor->oldRawData(), &originalColor);

                            int newRed = CLAMP(originalColor.red() + Bright, 0, quint8_MAX);
                            int newGreen = CLAMP(originalColor.green() + Bright, 0, quint8_MAX);
                            int newBlue = CLAMP(originalColor.blue() + Bright, 0, quint8_MAX);

                            QColor newColor;
                            newColor.setRgb(newRed, newGreen, newBlue);

                            dstAccessor->moveTo(dstTopLeft.x() + n, dstTopLeft.y() + m);
                            cs->fromQColor(newColor, dstAccessor->rawData());
                        }
                    }
                }
            }
        }

        BlurRadius = NewSize / 25 + 1;

        for (i = -1 * halfSize - BlurRadius ; (i < NewSize - halfSize + BlurRadius) && !(progressUpdater && progressUpdater->interrupted()) ; i++) {
            for (j = -1 * halfSize - BlurRadius;
                    ((j < NewSize - halfSize + BlurRadius) && !(progressUpdater && progressUpdater->interrupted()));
                    ++j) {
                r = sqrt(i * i + j * j);

                if (r <= Radius * 1.1) {
                    R = G = B = 0;
                    BlurPixels = 0;

                    for (k = -1 * BlurRadius; k < BlurRadius + 1; k++)
                        for (l = -1 * BlurRadius; l < BlurRadius + 1; l++) {
                            m = x + i + k;
                            n = y + j + l;

                            if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) {
                                QColor color;
                                dstAccessor->moveTo(dstTopLeft.x() + n, dstTopLeft.y() + m);
                                cs->toQColor(dstAccessor->rawData(), &color);

                                R += color.red();
                                G += color.green();
                                B += color.blue();
                                BlurPixels++;
                            }
                        }

                    m = x + i;
                    n = y + j;

                    if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) {
                        QColor color;

                        color.setRgb((int)(R / BlurPixels), (int)(G / BlurPixels), (int)(B / BlurPixels));
                        dstAccessor->moveTo(dstTopLeft.x() + n, dstTopLeft.y() + m);
                        cs->fromQColor(color, dstAccessor->rawData());
                    }
                }
            }
        }

        if (progressUpdater) progressUpdater->setValue(++count);
    }

    FreeBoolArray(BoolMatrix, Width);
}
Esempio n. 12
0
void KisPaintDeviceTest::testWrappedRandomAccessor()
{
    const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
    KisPaintDeviceSP dev = createWrapAroundPaintDevice(cs);

    KoColor c1(Qt::red, cs);
    KoColor c2(Qt::green, cs);

    dev->setPixel(3, 3, c1);
    dev->setPixel(18, 18, c2);

    const int pixelSize = dev->pixelSize();

    int x;
    int y;

    x = 3;
    y = 3;
    KisRandomAccessorSP dstIt = dev->createRandomAccessorNG(x, y);

    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = 23;
    y = 23;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = 3;
    y = 23;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = 23;
    y = 3;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = -17;
    y = 3;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = 3;
    y = -17;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);

    x = -17;
    y = -17;
    dstIt->moveTo(x, y);
    QVERIFY(!memcmp(dstIt->rawData(), c1.data(), pixelSize));
    QCOMPARE(dstIt->numContiguousColumns(x), 17);
    QCOMPARE(dstIt->numContiguousRows(y), 17);
}
Esempio n. 13
0
void HairyBrush::paintLine(KisPaintDeviceSP dab, KisPaintDeviceSP layer, const KisPaintInformation &pi1, const KisPaintInformation &pi2, qreal scale, qreal rotation)
{
    m_counter++;

    qreal x1 = pi1.pos().x();
    qreal y1 = pi1.pos().y();

    qreal x2 = pi2.pos().x();
    qreal y2 = pi2.pos().y();

    qreal dx = x2 - x1;
    qreal dy = y2 - y1;

    // TODO:this angle is different from the drawing angle in sensor (info.angle()). The bug is caused probably due to
    // not computing the drag vector properly in paintBezierLine when smoothing is used
    //qreal angle = atan2(dy, dx);
    qreal angle = rotation;

    qreal mousePressure = 1.0;
    if (m_properties->useMousePressure) { // want pressure from mouse movement
        qreal distance = sqrt(dx * dx + dy * dy);
        mousePressure = (1.0 - computeMousePressure(distance));
        scale *= mousePressure;
    }
    // this pressure controls shear and ink depletion
    qreal pressure = mousePressure * (pi2.pressure() * 2);

    Bristle *bristle = 0;
    KoColor bristleColor(dab->colorSpace());

    m_dabAccessor = dab->createRandomAccessorNG((int)x1, (int)y1);

    m_dab = dab;

    // initialization block
    if (firstStroke()) {
        initAndCache();
    }

    // if this is first time the brush touches the canvas and we use soak the ink from canvas
    if (firstStroke() && m_properties->useSoakInk) {
        if (layer) {
            colorifyBristles(layer, pi1.pos());
        }
        else {
            dbgKrita << "Can't soak the ink from the layer";
        }
    }

    KisRandomSourceSP randomSource = pi2.randomSource();

    qreal fx1, fy1, fx2, fy2;
    qreal randomX, randomY;
    qreal shear;

    float inkDeplation = 0.0;
    int inkDepletionSize = m_properties->inkDepletionCurve.size();
    int bristleCount = m_bristles.size();
    int bristlePathSize;
    qreal treshold = 1.0 - pi2.pressure();
    for (int i = 0; i < bristleCount; i++) {

        if (!m_bristles.at(i)->enabled()) continue;
        bristle = m_bristles[i];

        randomX = (randomSource->generateNormalized() * 2 - 1.0) * m_properties->randomFactor;
        randomY = (randomSource->generateNormalized() * 2 - 1.0) * m_properties->randomFactor;

        shear = pressure * m_properties->shearFactor;

        m_transform.reset();
        m_transform.rotateRadians(-angle);
        m_transform.scale(scale, scale);
        m_transform.translate(randomX, randomY);
        m_transform.shear(shear, shear);

        if (firstStroke() || (!m_properties->connectedPath)) {
            // transform start dab
            m_transform.map(bristle->x(), bristle->y(), &fx1, &fy1);
            // transform end dab
            m_transform.map(bristle->x(), bristle->y(), &fx2, &fy2);
        }
        else {
            // continue the path of the bristle from the previous position
            fx1 = bristle->prevX();
            fy1 = bristle->prevY();
            m_transform.map(bristle->x(), bristle->y(), &fx2, &fy2);
        }
        // remember the end point
        bristle->setPrevX(fx2);
        bristle->setPrevY(fy2);

        // all coords relative to device position
        fx1 += x1;
        fy1 += y1;

        fx2 += x2;
        fy2 += y2;

        if (m_properties->threshold && (bristle->length() < treshold)) continue;
        // paint between first and last dab
        const QVector<QPointF> bristlePath = m_trajectory.getLinearTrajectory(QPointF(fx1, fy1), QPointF(fx2, fy2), 1.0);
        bristlePathSize = m_trajectory.size();

        memcpy(bristleColor.data(), bristle->color().data() , m_pixelSize);
        for (int i = 0; i < bristlePathSize ; i++) {

            if (m_properties->inkDepletionEnabled) {
                inkDeplation = fetchInkDepletion(bristle, inkDepletionSize);

                if (m_properties->useSaturation && m_transfo != 0) {
                    saturationDepletion(bristle, bristleColor, pressure, inkDeplation);
                }

                if (m_properties->useOpacity) {
                    opacityDepletion(bristle, bristleColor, pressure, inkDeplation);
                }

            }
            else {
                if (bristleColor.opacityU8() != 0) {
                    bristleColor.setOpacity(bristle->length());
                }
            }

            addBristleInk(bristle, bristlePath.at(i), bristleColor);
            bristle->setInkAmount(1.0 - inkDeplation);
            bristle->upIncrement();
        }

    }
    m_dab = 0;
    m_dabAccessor = 0;
}