Beispiel #1
0
void KisScanlineFill::fillSelection(KisPixelSelectionSP pixelSelection)
{
    KisRandomConstAccessorSP it = m_d->device->createRandomConstAccessorNG(m_d->startPoint.x(), m_d->startPoint.y());
    KoColor srcColor(it->rawDataConst(), m_d->device->colorSpace());

    const int pixelSize = m_d->device->pixelSize();

    if (pixelSize == 1) {
        SelectionPolicy<true, DifferencePolicyOptimized<quint8>, CopyToSelection>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setDestinationSelection(pixelSelection);
        runImpl(policy);
    } else if (pixelSize == 2) {
        SelectionPolicy<true, DifferencePolicyOptimized<quint16>, CopyToSelection>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setDestinationSelection(pixelSelection);
        runImpl(policy);
    } else if (pixelSize == 4) {
        SelectionPolicy<true, DifferencePolicyOptimized<quint32>, CopyToSelection>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setDestinationSelection(pixelSelection);
        runImpl(policy);
    } else if (pixelSize == 8) {
        SelectionPolicy<true, DifferencePolicyOptimized<quint64>, CopyToSelection>
              policy(m_d->device, srcColor, m_d->threshold);
        policy.setDestinationSelection(pixelSelection);
        runImpl(policy);
    } else {
        SelectionPolicy<true, DifferencePolicySlow, CopyToSelection>
              policy(m_d->device, srcColor, m_d->threshold);
        policy.setDestinationSelection(pixelSelection);
        runImpl(policy);
    }
}
Beispiel #2
0
void KisScanlineFill::fillColor(const KoColor &fillColor)
{
    KisRandomConstAccessorSP it = m_d->device->createRandomConstAccessorNG(m_d->startPoint.x(), m_d->startPoint.y());
    KoColor srcColor(it->rawDataConst(), m_d->device->colorSpace());

    const int pixelSize = m_d->device->pixelSize();

    if (pixelSize == 1) {
        SelectionPolicy<false, DifferencePolicyOptimized<quint8>, FillWithColor>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setFillColor(fillColor);
        runImpl(policy);
    } else if (pixelSize == 2) {
        SelectionPolicy<false, DifferencePolicyOptimized<quint16>, FillWithColor>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setFillColor(fillColor);
        runImpl(policy);
    } else if (pixelSize == 4) {
        SelectionPolicy<false, DifferencePolicyOptimized<quint32>, FillWithColor>
            policy(m_d->device, srcColor, m_d->threshold);
        policy.setFillColor(fillColor);
        runImpl(policy);
    } else if (pixelSize == 8) {
        SelectionPolicy<false, DifferencePolicyOptimized<quint64>, FillWithColor>
              policy(m_d->device, srcColor, m_d->threshold);
        policy.setFillColor(fillColor);
        runImpl(policy);
    } else {
        SelectionPolicy<false, DifferencePolicySlow, FillWithColor>
              policy(m_d->device, srcColor, m_d->threshold);
        policy.setFillColor(fillColor);
        runImpl(policy);
    }
}
// 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;
}
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;

}
KisImportExportFilter::ConversionStatus KisHeightMapExport::convert(const QByteArray& from, const QByteArray& to)
{
    dbgFile << "HeightMap export! From:" << from << ", To:" << to;

    if (from != "application/x-krita")
        return KisImportExportFilter::NotImplemented;

    KisDocument *inputDoc = inputDocument();
    QString filename = outputFile();

    if (!inputDoc)
        return KisImportExportFilter::NoDocumentCreated;

    if (filename.isEmpty()) return KisImportExportFilter::FileNotFound;

    KisImageWSP image = inputDoc->image();
    Q_CHECK_PTR(image);

    if (inputDoc->image()->width() != inputDoc->image()->height()) {
        inputDoc->setErrorMessage(i18n("Cannot export this image to a heightmap: it is not square"));
        return KisImportExportFilter::WrongFormat;
    }

    if (inputDoc->image()->colorSpace()->colorModelId() != GrayAColorModelID) {
        inputDoc->setErrorMessage(i18n("Cannot export this image to a heightmap: it is not grayscale"));
        return KisImportExportFilter::WrongFormat;
    }

    KoDialog* kdb = new KoDialog(0);
    kdb->setWindowTitle(i18n("HeightMap Export Options"));
    kdb->setButtons(KoDialog::Ok | KoDialog::Cancel);

    Ui::WdgOptionsHeightMap optionsHeightMap;

    QWidget* wdg = new QWidget(kdb);
    optionsHeightMap.setupUi(wdg);

    kdb->setMainWidget(wdg);
    QApplication::restoreOverrideCursor();

    QString filterConfig = KisConfig().exportConfiguration("HeightMap");
    KisPropertiesConfiguration cfg;
    cfg.fromXML(filterConfig);

    optionsHeightMap.intSize->setValue(image->width());

    int endianness = cfg.getInt("endianness", 0);
    QDataStream::ByteOrder bo = QDataStream::LittleEndian;
    optionsHeightMap.radioPC->setChecked(true);

    if (endianness == 0) {
        bo = QDataStream::BigEndian;
        optionsHeightMap.radioMac->setChecked(true);
    }

    if (!getBatchMode()) {
        if (kdb->exec() == QDialog::Rejected) {
            return KisImportExportFilter::UserCancelled;
        }
    }

    if (optionsHeightMap.radioMac->isChecked()) {
        cfg.setProperty("endianness", 0);
        bo = QDataStream::BigEndian;
    }
    else {
        cfg.setProperty("endianness", 1);
        bo = QDataStream::LittleEndian;
    }
    KisConfig().setExportConfiguration("HeightMap", cfg);

    bool downscale = false;
    if (to == "image/x-r8" && image->colorSpace()->colorDepthId() == Integer16BitsColorDepthID) {

        downscale = (QMessageBox::question(0,
                                           i18nc("@title:window", "Downscale Image"),
                                           i18n("You specified the .r8 extension for a 16 bit/channel image. Do you want to save as 8 bit? Your image data will not be changed."),
                                           QMessageBox::Yes | QMessageBox::No)
                          == QMessageBox::Yes);
    }


    // the image must be locked at the higher levels
    KIS_SAFE_ASSERT_RECOVER_NOOP(image->locked());
    KisPaintDeviceSP pd = new KisPaintDevice(*image->projection());

    QFile f(filename);
    f.open(QIODevice::WriteOnly);
    QDataStream s(&f);
    s.setByteOrder(bo);

    KisRandomConstAccessorSP it = pd->createRandomConstAccessorNG(0, 0);
    bool r16 = ((image->colorSpace()->colorDepthId() == Integer16BitsColorDepthID) && !downscale);
    for (int i = 0; i < image->height(); ++i) {
        for (int j = 0; j < image->width(); ++j) {
            it->moveTo(i, j);
            if (r16) {
                s << KoGrayU16Traits::gray(const_cast<quint8*>(it->rawDataConst()));
            }
            else {
                s << KoGrayU8Traits::gray(const_cast<quint8*>(it->rawDataConst()));
            }
        }
    }

    f.close();
    return KisImportExportFilter::OK;
}
void KisSmudgeRadiusOption::apply(KisPainter& painter, const KisPaintInformation& info, qreal scale, qreal posx, qreal posy,KisPaintDeviceSP dev) const
{
    double sliderValue = computeValue(info);
    int smudgeRadius = ((sliderValue * scale)*0.5)/100.0;//scale is diameter?


    KoColor color = painter.paintColor();
    if (smudgeRadius == 1) {
        dev->pixel(posx, posy, &color);
        painter.setPaintColor(color);
    } else {

        const KoColorSpace* cs = dev->colorSpace();
        int pixelSize = cs->pixelSize();

        quint8* data = new quint8[pixelSize];
        static quint8** pixels = new quint8*[2];
        qint16* weights = new qint16[2];

        pixels[1] = new quint8[pixelSize];
        pixels[0] = new quint8[pixelSize];

        int loop_increment = 1;
        if(smudgeRadius >= 8)
        {
            loop_increment = (2*smudgeRadius)/16;
        }
        int i = 0;
        int k = 0;
        int j = 0;
        KisRandomConstAccessorSP accessor = dev->createRandomConstAccessorNG(0, 0);
        KisCrossDeviceColorPickerInt colorPicker(painter.device(), color);
        colorPicker.pickColor(posx, posy, color.data());

        for (int y = 0; y <= smudgeRadius; y = y + loop_increment) {
            for (int x = 0; x <= smudgeRadius; x = x + loop_increment) {

                for(j = 0;j < 2;j++)
                {
                    if(j == 1)
                    {
                        y = y*(-1);
                    }
                    for(k = 0;k < 2;k++)
                    {
                        if(k == 1)
                        {
                            x = x*(-1);
                        }
                        accessor->moveTo(posx + x, posy + y);
                        memcpy(pixels[1], accessor->rawDataConst(), pixelSize);
                        if(i == 0)
                        {
                            memcpy(pixels[0],accessor->rawDataConst(),pixelSize);
                        }
                        if (x == 0 && y == 0) {
                            // Because the sum of the weights must be 255,
                            // we cheat a bit, and weigh the center pixel differently in order
                            // to sum to 255 in total
                            // It's -(counts -1), because we'll add the center one implicitly
                            // through that calculation
                            weights[1] = (255 - ((i + 1) * (255 /(i+2) )) );
                        } else {
                            weights[1] = 255 /(i+2);
                        }


                        i++;
                        if (i>smudgeRadius){i=0;}
                        weights[0] = 255 - weights[1];
                        const quint8** cpixels = const_cast<const quint8**>(pixels);
                        cs->mixColorsOp()->mixColors(cpixels, weights,2, data);
                        memcpy(pixels[0],data,pixelSize);


                    }
                    x = x*(-1);
                }
                y = y*(-1);
            }

        }

        KoColor color = KoColor(pixels[0],cs);
        painter.setPaintColor(color);

        for (int l = 0; l < 2; l++){
            delete[] pixels[l];
        }
        // delete[] pixels;
        delete[] data;
    }


}