void KisPaintDeviceTest::testMakeClone() { QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "hakonepa.png"); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintDeviceSP srcDev = new KisPaintDevice(cs); srcDev->convertFromQImage(image, 0); srcDev->move(10,10); const KoColorSpace * weirdCS = KoColorSpaceRegistry::instance()->lab16(); KisPaintDeviceSP dstDev = new KisPaintDevice(weirdCS); dstDev->move(1000,1000); QVERIFY(!dstDev->fastBitBltPossible(srcDev)); QRect cloneRect(100,100,200,200); QPoint errpoint; dstDev->makeCloneFrom(srcDev, cloneRect); QVERIFY(*dstDev->colorSpace() == *srcDev->colorSpace()); QCOMPARE(dstDev->pixelSize(), srcDev->pixelSize()); QCOMPARE(dstDev->x(), srcDev->x()); QCOMPARE(dstDev->y(), srcDev->y()); QCOMPARE(dstDev->exactBounds(), cloneRect); QImage srcImage = srcDev->convertToQImage(0, cloneRect.x(), cloneRect.y(), cloneRect.width(), cloneRect.height()); QImage dstImage = dstDev->convertToQImage(0, cloneRect.x(), cloneRect.y(), cloneRect.width(), cloneRect.height()); if (!TestUtil::compareQImages(errpoint, dstImage, srcImage)) { QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } }
void KisPaintDeviceTest::testCreation() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintDeviceSP dev = new KisPaintDevice(cs); QVERIFY(dev->objectName().isEmpty()); dev = new KisPaintDevice(cs); QVERIFY(*dev->colorSpace() == *cs); QVERIFY(dev->x() == 0); QVERIFY(dev->y() == 0); QVERIFY(dev->pixelSize() == cs->pixelSize()); QVERIFY(dev->channelCount() == cs->channelCount()); QVERIFY(dev->dataManager() != 0); KisImageSP image = new KisImage(0, 1000, 1000, cs, "merge test"); KisPaintLayerSP layer = new KisPaintLayer(image, "bla", 125); dev = new KisPaintDevice(layer.data(), cs); QVERIFY(*dev->colorSpace() == *cs); QVERIFY(dev->x() == 0); QVERIFY(dev->y() == 0); QVERIFY(dev->pixelSize() == cs->pixelSize()); QVERIFY(dev->channelCount() == cs->channelCount()); QVERIFY(dev->dataManager() != 0); // Let the layer go out of scope and see what happens { KisPaintLayerSP l2 = new KisPaintLayer(image, "blabla", 250); dev = new KisPaintDevice(l2.data(), cs); } }
void KisMultiwayCut::Private::maskOutKeyStroke(KisPaintDeviceSP keyStrokeDevice, KisPaintDeviceSP mask, const QRect &boundingRect) { KIS_ASSERT_RECOVER_RETURN(keyStrokeDevice->pixelSize() == 1); KIS_ASSERT_RECOVER_RETURN(mask->pixelSize() == 1); QRegion region = keyStrokeDevice->region() & mask->exactBounds() & boundingRect; Q_FOREACH (const QRect &rc, region.rects()) { KisSequentialIterator dstIt(keyStrokeDevice, rc); KisSequentialConstIterator mskIt(mask, rc); do { if (*mskIt.rawDataConst() > 0) { *dstIt.rawData() = 0; } } while (dstIt.nextPixel() && mskIt.nextPixel()); } }
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]; } }
void KisPaintDeviceTest::testColorSpaceConversion() { QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "tile.png"); const KoColorSpace* srcCs = KoColorSpaceRegistry::instance()->rgb8(); const KoColorSpace* dstCs = KoColorSpaceRegistry::instance()->lab16(); KisPaintDeviceSP dev = new KisPaintDevice(srcCs); dev->convertFromQImage(image, 0); dev->move(10, 10); // Unalign with tile boundaries KUndo2Command* cmd = dev->convertTo(dstCs); QCOMPARE(dev->exactBounds(), QRect(10, 10, image.width(), image.height())); QCOMPARE(dev->pixelSize(), dstCs->pixelSize()); QVERIFY(*dev->colorSpace() == *dstCs); delete cmd; }
KisPaintDeviceSP initAsymTestDevice(QRect &imageRect, int &pixelSize, QByteArray &initialData) { KisPaintDeviceSP dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8()); pixelSize = dev->pixelSize(); imageRect = QRect(0,0,5,5); initialData.resize(25 * pixelSize); quint8 *ptr = (quint8*) initialData.data(); for(int i = 0; i < 25; i++) { KoColor pixel(QColor(i,i,i,255), dev->colorSpace()); memcpy(ptr, pixel.data(), pixelSize); ptr += pixelSize; } dev->writeBytes((const quint8*)initialData.constData(), imageRect); return dev; }
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 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()); } }
void KisPixelizeFilter::process(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* configuration, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); Q_ASSERT(configuration); qint32 width = applyRect.width(); qint32 height = applyRect.height(); //read the filter configuration values from the KisFilterConfiguration object quint32 pixelWidth = configuration->getInt("pixelWidth", 10); quint32 pixelHeight = configuration->getInt("pixelHeight", 10); if (pixelWidth == 0) pixelWidth = 1; if (pixelHeight == 0) pixelHeight = 1; qint32 pixelSize = device->pixelSize(); QVector<qint32> average(pixelSize); qint32 count; if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } qint32 numberOfPixelsProcessed = 0; for (qint32 y = 0; y < height; y += pixelHeight - (y % pixelHeight)) { qint32 h = pixelHeight; h = qMin(h, height - y); for (qint32 x = 0; x < width; x += pixelWidth - (x % pixelWidth)) { qint32 w = pixelWidth; w = qMin(w, width - x); for (qint32 i = 0; i < pixelSize; i++) { average[i] = 0; } count = 0; //read KisRectConstIteratorSP srcIt = device->createRectConstIteratorNG(srcTopLeft.x() + x, srcTopLeft.y() + y, w, h); do { for (qint32 i = 0; i < pixelSize; i++) { average[i] += srcIt->oldRawData()[i]; } count++; } while (srcIt->nextPixel()); //average if (count > 0) { for (qint32 i = 0; i < pixelSize; i++) average[i] /= count; } //write KisRectIteratorSP dstIt = device->createRectIteratorNG(srcTopLeft.x() + x, srcTopLeft.y() + y, w, h); do { for (int i = 0; i < pixelSize; i++) { dstIt->rawData()[i] = average[i]; } } while (dstIt->nextPixel()); if (progressUpdater) progressUpdater->setValue(++numberOfPixelsProcessed); } } }
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); }
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); } }
void cutOneWay(const KoColor &color, KisPaintDeviceSP src, KisPaintDeviceSP colorScribble, KisPaintDeviceSP backgroundScribble, KisPaintDeviceSP resultDevice, KisPaintDeviceSP maskDevice, const QRect &boundingRect) { using namespace boost; KIS_ASSERT_RECOVER_RETURN(src->pixelSize() == 1); KIS_ASSERT_RECOVER_RETURN(colorScribble->pixelSize() == 1); KIS_ASSERT_RECOVER_RETURN(backgroundScribble->pixelSize() == 1); KIS_ASSERT_RECOVER_RETURN(maskDevice->pixelSize() == 1); KIS_ASSERT_RECOVER_RETURN(*resultDevice->colorSpace() == *color.colorSpace()); KisLazyFillCapacityMap capacityMap(src, colorScribble, backgroundScribble, maskDevice, boundingRect); KisLazyFillGraph &graph = capacityMap.graph(); std::vector<default_color_type> groups(num_vertices(graph)); std::vector<int> residual_capacity(num_edges(graph), 0); std::vector<typename graph_traits<KisLazyFillGraph>::vertices_size_type> distance_vec(num_vertices(graph), 0); std::vector<typename graph_traits<KisLazyFillGraph>::edge_descriptor> predecessor_vec(num_vertices(graph)); auto vertexIndexMap = get(boost::vertex_index, graph); typedef KisLazyFillGraph::vertex_descriptor Vertex; Vertex s(Vertex::LABEL_A); Vertex t(Vertex::LABEL_B); float maxFlow = boykov_kolmogorov_max_flow(graph, capacityMap, make_iterator_property_map(&residual_capacity[0], get(boost::edge_index, graph)), get(boost::edge_reverse, graph), make_iterator_property_map(&predecessor_vec[0], vertexIndexMap), make_iterator_property_map(&groups[0], vertexIndexMap), make_iterator_property_map(&distance_vec[0], vertexIndexMap), vertexIndexMap, s, t); Q_UNUSED(maxFlow); KisSequentialIterator dstIt(resultDevice, graph.rect()); KisSequentialIterator mskIt(maskDevice, graph.rect()); const int pixelSize = resultDevice->pixelSize(); do { KisLazyFillGraph::vertex_descriptor v(dstIt.x(), dstIt.y()); long vertex_idx = get(boost::vertex_index, graph, v); default_color_type label = groups[vertex_idx]; if (label == black_color) { memcpy(dstIt.rawData(), color.data(), pixelSize); *mskIt.rawData() = 10 + (int(label) << 4); } } while (dstIt.nextPixel() && mskIt.nextPixel()); }
bool KisTIFFWriterVisitor::saveLayerProjection(KisLayer *layer) { dbgFile << "visiting on layer" << layer->name() << ""; KisPaintDeviceSP pd = layer->projection(); // Save depth int depth = 8 * pd->pixelSize() / pd->channelCount(); TIFFSetField(image(), TIFFTAG_BITSPERSAMPLE, depth); // Save number of samples if (m_options->alpha) { TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->channelCount()); uint16 sampleinfo[1] = { EXTRASAMPLE_UNASSALPHA }; TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 1, sampleinfo); } else { TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->channelCount() - 1); TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 0); } // Save colorspace information uint16 color_type; uint16 sample_format = SAMPLEFORMAT_UINT; if (!writeColorSpaceInformation(image(), pd->colorSpace(), color_type, sample_format)) { // unsupported colorspace return false; } TIFFSetField(image(), TIFFTAG_PHOTOMETRIC, color_type); TIFFSetField(image(), TIFFTAG_SAMPLEFORMAT, sample_format); TIFFSetField(image(), TIFFTAG_IMAGEWIDTH, layer->image()->width()); TIFFSetField(image(), TIFFTAG_IMAGELENGTH, layer->image()->height()); // Set the compression options TIFFSetField(image(), TIFFTAG_COMPRESSION, m_options->compressionType); TIFFSetField(image(), TIFFTAG_FAXMODE, m_options->faxMode); TIFFSetField(image(), TIFFTAG_JPEGQUALITY, m_options->jpegQuality); TIFFSetField(image(), TIFFTAG_ZIPQUALITY, m_options->deflateCompress); TIFFSetField(image(), TIFFTAG_PIXARLOGQUALITY, m_options->pixarLogCompress); // Set the predictor TIFFSetField(image(), TIFFTAG_PREDICTOR, m_options->predictor); // Use contiguous configuration TIFFSetField(image(), TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); // Use 8 rows per strip TIFFSetField(image(), TIFFTAG_ROWSPERSTRIP, 8); // Save profile if (m_options->saveProfile) { const KoColorProfile* profile = pd->colorSpace()->profile(); if (profile && profile->type() == "icc" && !profile->rawData().isEmpty()) { QByteArray ba = profile->rawData(); TIFFSetField(image(), TIFFTAG_ICCPROFILE, ba.size(), ba.constData()); } } tsize_t stripsize = TIFFStripSize(image()); tdata_t buff = _TIFFmalloc(stripsize); qint32 height = layer->image()->height(); qint32 width = layer->image()->width(); bool r = true; for (int y = 0; y < height; y++) { KisHLineConstIteratorSP it = pd->createHLineConstIteratorNG(0, y, width); switch (color_type) { case PHOTOMETRIC_MINISBLACK: { quint8 poses[] = { 0, 1 }; r = copyDataToStrips(it, buff, depth, sample_format, 1, poses); } break; case PHOTOMETRIC_RGB: { quint8 poses[4]; if (sample_format == SAMPLEFORMAT_IEEEFP) { poses[2] = 2; poses[1] = 1; poses[0] = 0; poses[3] = 3; } else { poses[0] = 2; poses[1] = 1; poses[2] = 0; poses[3] = 3; } r = copyDataToStrips(it, buff, depth, sample_format, 3, poses); } break; case PHOTOMETRIC_SEPARATED: { quint8 poses[] = { 0, 1, 2, 3, 4 }; r = copyDataToStrips(it, buff, depth, sample_format, 4, poses); } break; case PHOTOMETRIC_ICCLAB: { quint8 poses[] = { 0, 1, 2, 3 }; r = copyDataToStrips(it, buff, depth, sample_format, 3, poses); } break; return false; } if (!r) return false; TIFFWriteScanline(image(), buff, y, (tsample_t) - 1); } _TIFFfree(buff); TIFFWriteDirectory(image()); return true; }
void KisCubismFilter::cubism(KisPaintDeviceSP src, const QPoint& srcTopLeft, KisPaintDeviceSP dst, const QPoint& dstTopLeft, const QSize& size, quint32 tileSize, quint32 tileSaturation) const { Q_ASSERT(src); Q_ASSERT(dst); //fill the destination image with the background color (black for now) KisRectIteratorPixel dstIt = dst->createRectIterator(dstTopLeft.x(), dstTopLeft.y(), size.width(), size.height()); qint32 depth = src->colorSpace()->colorChannelCount(); while (! dstIt.isDone()) { for (qint32 i = 0; i < depth; i++) { dstIt.rawData()[i] = 0; } ++dstIt; } //compute number of rows and columns qint32 cols = (size.width() + tileSize - 1) / tileSize; qint32 rows = (size.height() + tileSize - 1) / tileSize; qint32 numTiles = (rows + 1) * (cols + 1); // setProgressTotalSteps(numTiles); // setProgressStage(i18n("Applying cubism filter..."),0); qint32* randomIndices = new qint32[numTiles]; for (qint32 i = 0; i < numTiles; i++) { randomIndices[i] = i; } randomizeIndices(numTiles, randomIndices); qint32 count = 0; qint32 i, j, ix, iy; double x, y, width, height, theta; KisPolygon *poly = new KisPolygon(); qint32 pixelSize = src->pixelSize(); const quint8 *srcPixel /*= new quint8[ pixelSize ]*/; quint8 *dstPixel = 0; KisRandomAccessor srcAccessor = src->createRandomAccessor(0, 0); while (count < numTiles) { i = randomIndices[count] / (cols + 1); j = randomIndices[count] % (cols + 1); x = j * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize / 2.0) + dstTopLeft.x(); y = i * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize / 2.0) + dstTopLeft.y(); width = (tileSize + randomDoubleNumber(0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation; height = (tileSize + randomDoubleNumber(0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation; theta = randomDoubleNumber(0, 2 * M_PI); poly->clear(); poly->addPoint(-width / 2.0, -height / 2.0); poly->addPoint(width / 2.0, -height / 2.0); poly->addPoint(width / 2.0, height / 2.0); poly->addPoint(-width / 2.0, height / 2.0); poly->rotate(theta); poly->translate(x, y); // bounds check on x, y ix = (qint32) CLAMP(x, dstTopLeft.x(), dstTopLeft.x() + size.width() - 1); iy = (qint32) CLAMP(y, dstTopLeft.y(), dstTopLeft.y() + size.height() - 1); //read the pixel at ix, iy srcAccessor.moveTo(ix, iy); srcPixel = srcAccessor.rawData(); if (srcPixel[pixelSize - 1]) { fillPolyColor(src, srcTopLeft, dst, dstTopLeft, size, poly, srcPixel, dstPixel); } count++; // if ((count % 5) == 0) setProgress(count); } }
void KisCubismFilter::fillPolyColor(KisPaintDeviceSP src, const QPoint& srcTopLeft, KisPaintDeviceSP dst, const QPoint & dstTopLeft, const QSize& size, KisPolygon* poly, const quint8* col, quint8* dest) const // void KisCubismFilter::fillPolyColor (KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPolygon* poly, const quint8* col, quint8* /*s*/, QRect rect) const { Q_UNUSED(srcTopLeft); Q_UNUSED(dest); qint32 val; double alpha; qint32 x, y; double xx, yy; double vec[2]; QRect rect(dstTopLeft, size); qint32 x1 = rect.left(), y1 = rect.top(), x2 = rect.right(), y2 = rect.bottom(); // qint32 selWidth, selHeight; qint32 *vals, *valsIter, *valsEnd; qint32 xs, ys, xe, ye; qint32 sx = (qint32)(*poly)[0].x(); qint32 sy = (qint32)(*poly)[0].y(); qint32 ex = (qint32)(*poly)[1].x(); qint32 ey = (qint32)(*poly)[1].y(); double dist = sqrt((double)(SQR(ex - sx) + SQR(ey - sy))); double oneOverDist = 0.0; if (dist > 0.0) { double oneOverDist = 1 / dist; vec[0] = (ex - sx) * oneOverDist; vec[1] = (ey - sy) * oneOverDist; } qint32 pixelSize = src->pixelSize(); //get the extents of the polygon double dMinX, dMinY, dMaxX, dMaxY; poly->extents(dMinX, dMinY, dMaxX, dMaxY); qint32 minX = static_cast<qint32>(dMinX); qint32 minY = static_cast<qint32>(dMinY); qint32 maxX = static_cast<qint32>(dMaxX); qint32 maxY = static_cast<qint32>(dMaxY); qint32 sizeX = (maxX - minX) * SUPERSAMPLE; qint32 sizeY = (maxY - minY) * SUPERSAMPLE; qint32 *minScanlines = new qint32[sizeY]; qint32 *minScanlinesIter = minScanlines; qint32 *maxScanlines = new qint32[sizeY]; qint32 *maxScanlinesIter = maxScanlines; for (qint32 i = 0; i < sizeY; i++) { minScanlines[i] = maxX * SUPERSAMPLE; maxScanlines[i] = minX * SUPERSAMPLE; } if (poly->numberOfPoints()) { qint32 polyNpts = poly->numberOfPoints(); xs = static_cast<qint32>((*poly)[polyNpts-1].x()); ys = static_cast<qint32>((*poly)[polyNpts-1].y()); xe = static_cast<qint32>((*poly)[0].x()); ye = static_cast<qint32>((*poly)[0].y()); xs *= SUPERSAMPLE; ys *= SUPERSAMPLE; xe *= SUPERSAMPLE; ye *= SUPERSAMPLE; convertSegment(xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE); KisPolygon::iterator it; for (it = poly->begin(); it != poly->end();) { xs = static_cast<qint32>((*it).x()); ys = static_cast<qint32>((*it).y()); ++it; if (it != poly->end()) { xe = static_cast<qint32>((*it).x()); ye = static_cast<qint32>((*it).y()); xs *= SUPERSAMPLE; ys *= SUPERSAMPLE; xe *= SUPERSAMPLE; ye *= SUPERSAMPLE; convertSegment(xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE); } } } KisRandomAccessor dstAccessor = dst->createRandomAccessor(0, 0); KoMixColorsOp * mixOp = src->colorSpace()->mixColorsOp(); quint8* buf = new quint8[pixelSize]; vals = new qint32[sizeX]; // x1 = minX; x2 = maxX; y1 = minY; y2 = maxY; for (qint32 i = 0; i < sizeY; i++, minScanlinesIter++, maxScanlinesIter++) { if (!(i % SUPERSAMPLE)) { memset(vals, 0, sizeof(qint32) * sizeX); } yy = static_cast<double>(i) / static_cast<double>(SUPERSAMPLE) + minY; for (qint32 j = *minScanlinesIter; j < *maxScanlinesIter; j++) { x = j - minX * SUPERSAMPLE; vals[x] += 255; } if (!((i + 1) % SUPERSAMPLE)) { y = (i / SUPERSAMPLE) + minY; if (y >= y1 && y <= y2) { for (qint32 j = 0; j < sizeX; j += SUPERSAMPLE) { x = (j / SUPERSAMPLE) + minX; if (x >= x1 && x <= x2) { for (val = 0, valsIter = &vals[j], valsEnd = &valsIter[SUPERSAMPLE]; valsIter < valsEnd; valsIter++) { val += *valsIter; } val /= SQR(SUPERSAMPLE); if (val > 0) { xx = static_cast<double>(j) / static_cast<double>(SUPERSAMPLE) + minX; alpha = calcAlphaBlend(vec, oneOverDist, xx - sx, yy - sy); qint16 weights[2]; weights[0] = static_cast<quint8>(alpha * 255); weights[1] = 255 - weights[0]; dstAccessor.moveTo(x, y); memcpy(buf, dstAccessor.rawData(), sizeof(quint8) * pixelSize); const quint8* colors[2]; colors[0] = col; colors[1] = buf; mixOp->mixColors(colors, weights, 2, dstAccessor.rawData()); } } } } } } delete[] buf; delete[] vals; delete[] minScanlines; delete[] maxScanlines; }
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; }
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 }
void KisSobelFilter::process(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* configuration, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(!device.isNull()); //read the filter configuration values from the KisFilterConfiguration object bool doHorizontal = configuration->getBool("doHorizontally", true); bool doVertical = configuration->getBool("doVertically", true); bool keepSign = configuration->getBool("keepSign", true); bool makeOpaque = configuration->getBool("makeOpaque", true); quint32 width = applyRect.width(); quint32 height = applyRect.height(); quint32 pixelSize = device->pixelSize(); int cost = applyRect.height(); /* allocate row buffers */ quint8* prevRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(prevRow); quint8* curRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(curRow); quint8* nextRow = new quint8[(width + 2) * pixelSize]; Q_CHECK_PTR(nextRow); quint8* dest = new quint8[ width * pixelSize]; Q_CHECK_PTR(dest); quint8* pr = prevRow + pixelSize; quint8* cr = curRow + pixelSize; quint8* nr = nextRow + pixelSize; prepareRow(device, pr, srcTopLeft.x(), srcTopLeft.y() - 1, width, height); prepareRow(device, cr, srcTopLeft.x(), srcTopLeft.y(), width, height); quint32 counter = 0; quint8* d; quint8* tmp; qint32 gradient, horGradient, verGradient; // loop through the rows, applying the sobel convolution KisHLineIteratorSP dstIt = device->createHLineIteratorNG(srcTopLeft.x(), srcTopLeft.y(), width); for (quint32 row = 0; row < height; row++) { // prepare the next row prepareRow(device, nr, srcTopLeft.x(), srcTopLeft.y() + row + 1, width, height); d = dest; for (quint32 col = 0; col < width * pixelSize; col++) { int positive = col + pixelSize; int negative = col - pixelSize; horGradient = (doHorizontal ? ((pr[negative] + 2 * pr[col] + pr[positive]) - (nr[negative] + 2 * nr[col] + nr[positive])) : 0); verGradient = (doVertical ? ((pr[negative] + 2 * cr[negative] + nr[negative]) - (pr[positive] + 2 * cr[positive] + nr[positive])) : 0); gradient = (qint32)((doVertical && doHorizontal) ? (ROUND(RMS(horGradient, verGradient)) / 5.66) // always >0 : (keepSign ? (127 + (ROUND((horGradient + verGradient) / 8.0))) : (ROUND(qAbs(horGradient + verGradient) / 4.0)))); *d++ = gradient; if (gradient > 10) counter ++; } // shuffle the row pointers tmp = pr; pr = cr; cr = nr; nr = tmp; //store the dest device->writeBytes(dest, srcTopLeft.x(), row, width, 1); if (makeOpaque) { do { device->colorSpace()->setOpacity(dstIt->rawData(), OPACITY_OPAQUE_U8, 1); } while(dstIt->nextPixel()); dstIt->nextRow(); } if (progressUpdater) progressUpdater->setProgress(row / cost); } delete[] prevRow; delete[] curRow; delete[] nextRow; delete[] dest; }