Esempio n. 1
0
// gmic assumes float rgba in 0.0 - 255.0, thus default value
void KisGmicSimpleConvertor::convertToGmicImage(KisPaintDeviceSP dev, gmic_image<float>& gmicImage, QRect rc)
{
    Q_ASSERT(!dev.isNull());
    Q_ASSERT(gmicImage._spectrum == 4); // rgba

    if (rc.isEmpty())
    {
        rc = QRect(0,0,gmicImage._width, gmicImage._height);
    }

    const KoColorSpace *rgbaFloat32bitcolorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
                                                                                                Float32BitsColorDepthID.id(),
                                                                                                KoColorSpaceRegistry::instance()->rgb8()->profile());
    Q_CHECK_PTR(rgbaFloat32bitcolorSpace);

    int greenOffset = gmicImage._width * gmicImage._height;
    int blueOffset = greenOffset * 2;
    int alphaOffset = greenOffset * 3;

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

    const KoColorSpace * colorSpace = dev->colorSpace();
    KisRandomConstAccessorSP it = dev->createRandomConstAccessorNG(0,0);

    int optimalBufferSize = 64; // most common numContiguousColumns, tile size?
    quint8 * floatRGBApixel = new quint8[rgbaFloat32bitcolorSpace->pixelSize() * optimalBufferSize];
    quint32 pixelSize = rgbaFloat32bitcolorSpace->pixelSize();
    int pos = 0;
    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);

            colorSpace->convertPixelsTo(it->rawDataConst(), floatRGBApixel, rgbaFloat32bitcolorSpace, numContiguousColumns, renderingIntent, conversionFlags);

            pos = y * gmicImage._width + x;
            for (qint32 bx = 0; bx < numContiguousColumns; bx++)
            {
                memcpy(gmicImage._data + pos                  ,floatRGBApixel + bx * pixelSize   , 4);
                memcpy(gmicImage._data + pos + greenOffset    ,floatRGBApixel + bx * pixelSize + 4, 4);
                memcpy(gmicImage._data + pos + blueOffset     ,floatRGBApixel + bx * pixelSize + 8, 4);
                memcpy(gmicImage._data + pos + alphaOffset    ,floatRGBApixel + bx * pixelSize + 12, 4);
                pos++;
            }

            x += numContiguousColumns;
        }
    }
    delete [] floatRGBApixel;
}
Esempio n. 2
0
void KisGmicSimpleConvertor::convertToGmicImageFast(KisPaintDeviceSP dev, CImg< float >& gmicImage, QRect rc)
{
    KoColorTransformation * pixelToGmicPixelFormat = createTransformation(dev->colorSpace());
    if (pixelToGmicPixelFormat == 0)
    {
        dbgPlugins << "Fall-back to slow color conversion method";
        convertToGmicImage(dev, gmicImage, rc);
        return;
    }

    if (rc.isEmpty())
    {
        dbgPlugins << "Image rectangle is empty! Using supplied gmic layer dimension";
        rc = QRect(0,0,gmicImage._width, gmicImage._height);
    }

    qint32 x = rc.x();
    qint32 y = rc.y();
    qint32 width = rc.width();
    qint32 height = rc.height();

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

    const qint32 numChannels = 4;

    int greenOffset = gmicImage._width * gmicImage._height;
    int blueOffset = greenOffset * 2;
    int alphaOffset = greenOffset * 3;

    QVector<float *> planes;
    planes.append(gmicImage._data);
    planes.append(gmicImage._data + greenOffset);
    planes.append(gmicImage._data + blueOffset);
    planes.append(gmicImage._data + alphaOffset);

    KisRandomConstAccessorSP it = dev->createRandomConstAccessorNG(dev->x(), dev->y());
    int tileWidth = it->numContiguousColumns(dev->x());
    int tileHeight = it->numContiguousRows(dev->y());

    Q_ASSERT(tileWidth == 64);
    Q_ASSERT(tileHeight == 64);

    const KoColorSpace *rgbaFloat32bitcolorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
                                                                                                Float32BitsColorDepthID.id(),
                                                                                                KoColorSpaceRegistry::instance()->rgb8()->profile());
    Q_CHECK_PTR(rgbaFloat32bitcolorSpace);
    const qint32 dstPixelSize = rgbaFloat32bitcolorSpace->pixelSize();
    const qint32 srcPixelSize = dev->pixelSize();

    quint8 * dstTile = new quint8[rgbaFloat32bitcolorSpace->pixelSize() * tileWidth * tileHeight];

    qint32 dataY = 0;
    qint32 imageX = x;
    qint32 imageY = y;
    it->moveTo(imageX, imageY);
    qint32 rowsRemaining = height;

    while (rowsRemaining > 0) {

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

        qint32 rowsToWork = qMin(numContiguousImageRows, rowsRemaining);
        qint32 convertedTileY = tileHeight - rowsToWork;
        Q_ASSERT(convertedTileY >= 0);

        while (columnsRemaining > 0) {

            qint32 numContiguousImageColumns = it->numContiguousColumns(imageX);
            qint32 columnsToWork = qMin(numContiguousImageColumns, columnsRemaining);
            qint32 convertedTileX = tileWidth - columnsToWork;
            Q_ASSERT(convertedTileX >= 0);

            const qint32 dataIdx = dataX + dataY * width;
            const qint32 dstTileIndex = convertedTileX + convertedTileY * tileWidth;
            const qint32 tileRowStride = (tileWidth - columnsToWork) * dstPixelSize;
            const qint32 srcTileRowStride = (tileWidth - columnsToWork) * srcPixelSize;

            it->moveTo(imageX, imageY);
            quint8 *tileItStart = dstTile + dstTileIndex * dstPixelSize;

            // transform tile row by row
            quint8 *dstTileIt = tileItStart;
            quint8 *srcTileIt = const_cast<quint8*>(it->rawDataConst());

            qint32 row = rowsToWork;
            while (row > 0)
            {
                pixelToGmicPixelFormat->transform(srcTileIt, dstTileIt , columnsToWork);
                srcTileIt += columnsToWork * srcPixelSize;
                srcTileIt += srcTileRowStride;

                dstTileIt += columnsToWork * dstPixelSize;
                dstTileIt += tileRowStride;

                row--;
            }

            // here we want to copy floats to dstTile, so tileItStart has to point to float buffer
            qint32 channelSize = sizeof(float);
            for(qint32 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(planeIt, tileIt, channelSize);
                        tileIt += dstPixelSize;
                        planeIt += 1;
                    }

                    tileIt += tileRowStride;
                    planeIt += dataStride;
                }
                // skip channel in tile: red, green, blue, alpha
                tileItStart += channelSize;
            }

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

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

    delete [] dstTile;
    delete pixelToGmicPixelFormat;

}