void KisConvolutionPainterTest::testSymmConvolution()
{
    qreal offset = 0.0;
    qreal factor = 1.0;
    Eigen::Matrix<qreal, 3, 3> filter = initSymmFilter(offset, factor);

    QRect imageRect;
    int pixelSize = 0;
    QByteArray initialData;
    KisPaintDeviceSP dev = initAsymTestDevice(imageRect, pixelSize, initialData);


    KisConvolutionKernelSP kernel =
        KisConvolutionKernel::fromMatrix(filter, offset, factor);
    KisConvolutionPainter gc(dev);
    gc.beginTransaction();

    QRect filterRect = imageRect.adjusted(1,1,-1,-1);
    gc.applyMatrix(kernel, dev, filterRect.topLeft(), filterRect.topLeft(),
                   filterRect.size());
    gc.deleteTransaction();

    QByteArray resultData(initialData.size(), 0);
    dev->readBytes((quint8*)resultData.data(), imageRect);

    QCOMPARE(resultData, initialData);
}
void KisConvolutionPainterTest::testAsymmConvolutionImp(QBitArray channelFlags)
{
    qreal offset = 0.0;
    qreal factor = 1.0;
    Eigen::Matrix<qreal, 3, 3> filter = initAsymmFilter(offset, factor);

    QRect imageRect;
    int pixelSize = -1;
    QByteArray initialData;
    KisPaintDeviceSP dev = initAsymTestDevice(imageRect, pixelSize, initialData);

    KisConvolutionKernelSP kernel =
        KisConvolutionKernel::fromMatrix(filter, offset, factor);
    KisConvolutionPainter gc(dev);
    gc.beginTransaction();
    gc.setChannelFlags(channelFlags);

    QRect filterRect = imageRect.adjusted(1,1,-1,-1);
    gc.applyMatrix(kernel, dev, filterRect.topLeft(), filterRect.topLeft(),
                   filterRect.size());
    gc.deleteTransaction();


    QByteArray resultData(initialData.size(), 0);
    dev->readBytes((quint8*)resultData.data(), imageRect);

    QRect filteredRect = imageRect.adjusted(1, 1, -1, -1);

    quint8 *srcPtr = (quint8*) initialData.data();
    quint8 *resPtr = (quint8*) resultData.data();

    for(int row = 0; row < imageRect.height(); row++) {
        for(int col = 0; col < imageRect.width(); col++) {

            bool isFiltered = filteredRect.contains(col, row);

            int pixelValue = 8 + row * imageRect.width() + col;
            KoColor filteredPixel(QColor(pixelValue, pixelValue, pixelValue, 255), dev->colorSpace());

            KoColor resultPixel(dev->colorSpace());
            for(int j = 0; j < pixelSize; j++) {
                resultPixel.data()[j] = isFiltered && channelFlags[j] ?
                    filteredPixel.data()[j] : srcPtr[j];
            }

            if(memcmp(resPtr, resultPixel.data(), pixelSize)) {
                printPixel("Actual:  ", pixelSize, resPtr);
                printPixel("Expected:", pixelSize, resultPixel.data());
                QFAIL("Failed to filter area");
            }

            srcPtr += pixelSize;
            resPtr += pixelSize;
        }
    }
}
示例#3
0
void checkReadWriteRoundTrip(KisPaintDeviceSP dev,
                             const QRect &rc)
{
    KisPaintDeviceSP deviceCopy = new KisPaintDevice(*dev.data());

    QRect readRect(10, 10, 20, 20);
    int bufSize = rc.width() * rc.height() * dev->pixelSize();

    QScopedPointer<quint8> buf1(new quint8[bufSize]);

    deviceCopy->readBytes(buf1.data(), rc);

    deviceCopy->clear();
    QVERIFY(deviceCopy->extent().isEmpty());


    QScopedPointer<quint8> buf2(new quint8[bufSize]);
    deviceCopy->writeBytes(buf1.data(), rc);
    deviceCopy->readBytes(buf2.data(), rc);

    QVERIFY(!memcmp(buf1.data(), buf2.data(), bufSize));
}
void KisSobelFilter::prepareRow(KisPaintDeviceSP src, quint8* data, quint32 x, quint32 y, quint32 w, quint32 h) const
{
    if (y > h - 1) y = h - 1;
    quint32 pixelSize = src->pixelSize();

    src->readBytes(data, x, y, w, 1);

    for (quint32 b = 0; b < pixelSize; b++) {
        int offset = pixelSize - b;
        data[-offset] = data[b];
        data[w * pixelSize + b] = data[(w - 1) * pixelSize + b];
    }
}
示例#5
0
//#define SAVE_OUTPUT_IMAGES
void KisAutoBrushTest::testCopyMasking()
{
    int w = 64;
    int h = 64;
    int x = 0;
    int y = 0;
    QRect rc(x, y, w, h);

    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();

    KoColor black(Qt::black, cs);
    KoColor red(Qt::red, cs);


    KisPaintDeviceSP tempDev = new KisPaintDevice(cs);
    tempDev->fill(0, 0, w, h, red.data());
#ifdef SAVE_OUTPUT_IMAGES
    tempDev->convertToQImage(0).save("tempDev.png");
#endif

    KisCircleMaskGenerator * mask = new KisCircleMaskGenerator(w, 1.0, 0.5, 0.5, 2, true);
    KisAutoBrush brush(mask, 0, 0);

    KisFixedPaintDeviceSP maskDab = new KisFixedPaintDevice(cs);
    brush.mask(maskDab, black, KisDabShape(), KisPaintInformation());
    maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8());

#ifdef SAVE_OUTPUT_IMAGES
    maskDab->convertToQImage(0, 0, 0, 64, 64).save("maskDab.png");
#endif

    QCOMPARE(tempDev->exactBounds(), rc);
    QCOMPARE(maskDab->bounds(), rc);

    KisFixedPaintDeviceSP dev2fixed = new KisFixedPaintDevice(cs);
    dev2fixed->setRect(rc);
    dev2fixed->initialize();
    tempDev->readBytes(dev2fixed->data(), rc);
    dev2fixed->convertToQImage(0).save("converted-tempDev-to-fixed.png");

    KisPaintDeviceSP dev = new KisPaintDevice(cs);
    KisPainter painter(dev);
    painter.setCompositeOp(COMPOSITE_COPY);
    painter.bltFixedWithFixedSelection(x, y, dev2fixed, maskDab, 0, 0, 0, 0, rc.width(), rc.height());
    //painter.bitBltWithFixedSelection(x, y, tempDev, maskDab, 0, 0, 0, 0, rc.width(), rc.height());

#ifdef SAVE_OUTPUT_IMAGES
    dev->convertToQImage(0).save("final.png");
#endif
}
示例#6
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();
    }

}
示例#7
0
void KisPaintDeviceTest::testRoundtripReadWrite()
{
    const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
    KisPaintDeviceSP dev = new KisPaintDevice(cs);
    QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "tile.png");
    dev->convertFromQImage(image, 0);

    quint8* bytes = new quint8[cs->pixelSize() * image.width() * image.height()];
    memset(bytes, 0, image.width() * image.height() * dev->pixelSize());
    dev->readBytes(bytes, image.rect());

    KisPaintDeviceSP dev2 = new KisPaintDevice(cs);
    dev2->writeBytes(bytes, image.rect());
    QVERIFY(dev2->exactBounds() == image.rect());

    dev2->convertToQImage(0, 0, 0, image.width(), image.height()).save("readwrite.png");


    QPoint pt;
    if (!TestUtil::comparePaintDevices(pt, dev, dev2)) {
        QFAIL(QString("Failed round trip using readBytes and writeBytes, first different pixel: %1,%2 ").arg(pt.x()).arg(pt.y()).toLatin1());
    }
}
示例#8
0
void KisImagePyramid::retrieveImageData(const QRect &rect)
{
    // XXX: use QThreadStorage to cache the two patches (512x512) of pixels. Note
    // that when we do that, we need to reset that cache when the projection's
    // colorspace changes.
    const KoColorSpace *projectionCs = m_originalImage->projection()->colorSpace();
    KisPaintDeviceSP originalProjection = m_originalImage->projection();
    quint32 numPixels = rect.width() * rect.height();

    QScopedArrayPointer<quint8> originalBytes(
        new quint8[originalProjection->colorSpace()->pixelSize() * numPixels]);

    originalProjection->readBytes(originalBytes.data(), rect);

    if (m_displayFilter &&
        m_useOcio &&
        projectionCs->colorModelId() == RGBAColorModelID) {

#ifdef HAVE_OCIO
        const KoColorProfile *destinationProfile =
            m_displayFilter->useInternalColorManagement() ?
            m_monitorProfile : projectionCs->profile();

        const KoColorSpace *floatCs =
            KoColorSpaceRegistry::instance()->colorSpace(
                RGBAColorModelID.id(),
                Float32BitsColorDepthID.id(),
                destinationProfile);

        const KoColorSpace *modifiedMonitorCs =
            KoColorSpaceRegistry::instance()->colorSpace(
                RGBAColorModelID.id(),
                Integer8BitsColorDepthID.id(),
                destinationProfile);

        if (projectionCs->colorDepthId() == Float32BitsColorDepthID) {
            m_displayFilter->filter(originalBytes.data(), numPixels);
        } else {
            QScopedArrayPointer<quint8> dst(new quint8[floatCs->pixelSize() * numPixels]);
            projectionCs->convertPixelsTo(originalBytes.data(), dst.data(), floatCs, numPixels, KoColorConversionTransformation::InternalRenderingIntent, KoColorConversionTransformation::InternalConversionFlags);
            m_displayFilter->filter(dst.data(), numPixels);
            originalBytes.swap(dst);
        }

        {
            QScopedArrayPointer<quint8> dst(new quint8[modifiedMonitorCs->pixelSize() * numPixels]);
            floatCs->convertPixelsTo(originalBytes.data(), dst.data(), modifiedMonitorCs, numPixels, KoColorConversionTransformation::InternalRenderingIntent, KoColorConversionTransformation::InternalConversionFlags);
            originalBytes.swap(dst);
        }
#endif
    }
    else {
        QList<KoChannelInfo*> channelInfo = projectionCs->channels();
        if (!m_channelFlags.size() == channelInfo.size()) {
            setChannelFlags(QBitArray());
        }
        if (!m_channelFlags.isEmpty() && !m_allChannelsSelected) {
            QScopedArrayPointer<quint8> dst(new quint8[projectionCs->pixelSize() * numPixels]);

            int channelSize = channelInfo[m_selectedChannelIndex]->size();
            int pixelSize = projectionCs->pixelSize();

            KisConfig cfg;

            if (m_onlyOneChannelSelected && !cfg.showSingleChannelAsColor()) {
                int selectedChannelPos = channelInfo[m_selectedChannelIndex]->pos();
                for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
                    for (uint channelIndex = 0; channelIndex < projectionCs->channelCount(); ++channelIndex) {

                        if (channelInfo[channelIndex]->channelType() == KoChannelInfo::COLOR) {
                            memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                   originalBytes.data() + (pixelIndex * pixelSize) + selectedChannelPos,
                                   channelSize);
                        }
                        else if (channelInfo[channelIndex]->channelType() == KoChannelInfo::ALPHA) {
                            memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                   originalBytes.data()  + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                   channelSize);
                        }
                    }
                }
            }
            else {
                for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
                    for (uint channelIndex = 0; channelIndex < projectionCs->channelCount(); ++channelIndex) {
                        if (m_channelFlags.testBit(channelIndex)) {
                            memcpy(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                   originalBytes.data()  + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                   channelSize);
                        }
                        else {
                            memset(dst.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), 0, channelSize);
                        }
                    }
                }

            }
            originalBytes.swap(dst);
        }

        QScopedArrayPointer<quint8> dst(new quint8[m_monitorColorSpace->pixelSize() * numPixels]);
        projectionCs->convertPixelsTo(originalBytes.data(), dst.data(), m_monitorColorSpace, numPixels, m_renderingIntent, m_conversionFlags);
        originalBytes.swap(dst);
    }

    m_pyramid[ORIGINAL_INDEX]->writeBytes(originalBytes.data(), rect);
}
示例#9
0
void KisPaintDeviceTest::testReadBytesWrapAround()
{
    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();

    {
        QRect readRect(10, 10, 20, 20);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final1.png");

        QVERIFY(memcmp(buf.data() + (7 + readRect.width() * 7) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (8 + readRect.width() * 8) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (12 + readRect.width() * 12) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (13 + readRect.width() * 13) * pixelSize, c1.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }

    {
        // check weird case when the read rect is larger than wrap rect
        QRect readRect(10, 10, 30, 30);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final2.png");

        QVERIFY(memcmp(buf.data() + (7 + readRect.width() * 7) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (8 + readRect.width() * 8) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (12 + readRect.width() * 12) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (13 + readRect.width() * 13) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (27 + readRect.width() * 7) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (28 + readRect.width() * 8) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (7 + readRect.width() * 27) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (8 + readRect.width() * 28) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (27 + readRect.width() * 27) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (28 + readRect.width() * 28) * pixelSize, c2.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }

    {
        // even more large
        QRect readRect(10, 10, 40, 40);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final3.png");

        QVERIFY(memcmp(buf.data() + (7 + readRect.width() * 7) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (8 + readRect.width() * 8) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (12 + readRect.width() * 12) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (13 + readRect.width() * 13) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (27 + readRect.width() * 7) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (28 + readRect.width() * 8) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (7 + readRect.width() * 27) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (8 + readRect.width() * 28) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (27 + readRect.width() * 27) * pixelSize, c2.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (28 + readRect.width() * 28) * pixelSize, c2.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (32 + readRect.width() * 12) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (33 + readRect.width() * 13) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (12 + readRect.width() * 32) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (13 + readRect.width() * 33) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (32 + readRect.width() * 32) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (33 + readRect.width() * 33) * pixelSize, c1.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }

    {
        // check if the wrap rect contains the read rect entirely
        QRect readRect(1, 1, 10, 10);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final4.png");

        QVERIFY(memcmp(buf.data() + (1 + readRect.width() * 1) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (2 + readRect.width() * 2) * pixelSize, c1.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }

    {
        // check if the wrap happens only on vertical side of the rect
        QRect readRect(1, 1, 29, 10);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final5.png");

        QVERIFY(memcmp(buf.data() + (1 + readRect.width() * 1) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (2 + readRect.width() * 2) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (21 + readRect.width() * 1) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (22 + readRect.width() * 2) * pixelSize, c1.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }

    {
        // check if the wrap happens only on horizontal side of the rect
        QRect readRect(1, 1, 10, 29);
        QScopedPointer<quint8> buf(new quint8[readRect.width() *
                                              readRect.height() *
                                              pixelSize]);
        dev->readBytes(buf.data(), readRect);
        //dev->convertToQImage(0, readRect.x(), readRect.y(), readRect.width(), readRect.height()).save("final6.png");

        QVERIFY(memcmp(buf.data() + (1 + readRect.width() * 1) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (2 + readRect.width() * 2) * pixelSize, c1.data(), pixelSize));

        QVERIFY(memcmp(buf.data() + (1 + readRect.width() * 21) * pixelSize, c1.data(), pixelSize));
        QVERIFY(!memcmp(buf.data() + (2 + readRect.width() * 22) * pixelSize, c1.data(), pixelSize));

        checkReadWriteRoundTrip(dev, readRect);
    }
}