void HairyBrush::fromDabWithDensity(KisFixedPaintDeviceSP dab, qreal density) { int width = dab->bounds().width(); int height = dab->bounds().height(); int centerX = width * 0.5; int centerY = height * 0.5; // make mask Bristle * bristle = 0; qreal alpha; quint8 * dabPointer = dab->data(); quint8 pixelSize = dab->pixelSize(); const KoColorSpace * cs = dab->colorSpace(); KoColor bristleColor(cs); srand48(12345678); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { alpha = cs->opacityF(dabPointer); if (alpha != 0.0){ if (density == 1.0 || drand48() <= density){ memcpy(bristleColor.data(), dabPointer, pixelSize); bristle = new Bristle(x - centerX, y - centerY, alpha); // using value from image as length of bristle bristle->setColor(bristleColor); m_bristles.append(bristle); } } dabPointer += pixelSize; } } }
void KisPressureSharpnessOption::applyThreshold(KisFixedPaintDeviceSP dab) { if (!isChecked()) return; const KoColorSpace * cs = dab->colorSpace(); // Set all alpha > opaque/2 to opaque, the rest to transparent. // XXX: Using 4/10 as the 1x1 circle brush paints nothing with 0.5. quint8* dabPointer = dab->data(); QRect rc = dab->bounds(); int pixelSize = dab->pixelSize(); int pixelCount = rc.width() * rc.height(); for (int i = 0; i < pixelCount; i++) { quint8 alpha = cs->opacityU8(dabPointer); if (alpha < (m_threshold * OPACITY_OPAQUE_U8) / 100) { cs->setOpacity(dabPointer, OPACITY_TRANSPARENT_U8, 1); } else { cs->setOpacity(dabPointer, OPACITY_OPAQUE_U8, 1); } dabPointer += pixelSize; } }
void KisFixedPaintDeviceTest::testColorSpaceConversion() { QImage image(QString(FILES_DATA_DIR) + QDir::separator() + "tile.png"); const KoColorSpace* srcCs = KoColorSpaceRegistry::instance()->rgb8(); const KoColorSpace* dstCs = KoColorSpaceRegistry::instance()->lab16(); KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(srcCs); dev->convertFromQImage(image, 0); dev->convertTo(dstCs); QVERIFY(dev->bounds() == QRect(0, 0, image.width(), image.height())); QVERIFY(dev->pixelSize() == dstCs->pixelSize()); QVERIFY(*dev->colorSpace() == *dstCs); }
void KisFixedPaintDeviceTest::testCreation() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisFixedPaintDeviceSP dev = new KisFixedPaintDevice(cs); dev = new KisFixedPaintDevice(cs); QVERIFY(dev->bounds() == QRect()); QVERIFY(*dev->colorSpace() == *cs); QVERIFY(dev->pixelSize() == cs->pixelSize()); dev->setRect(QRect(0, 0, 100, 100)); QVERIFY(dev->bounds() == QRect(0, 0, 100, 100)); dev->initialize(); QVERIFY(dev->data() != 0); quint8* data = dev->data(); for (uint i = 0; i < 100 * 100 * cs->pixelSize(); ++i) { QVERIFY(data[i] == 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(); } }
void KisAutoBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, double scaleX, double scaleY, double angle, const KisPaintInformation& info, double subPixelX , double subPixelY, qreal softnessFactor) const { Q_UNUSED(info); // Generate the paint device from the mask const KoColorSpace* cs = dst->colorSpace(); quint32 pixelSize = cs->pixelSize(); // mask dimension methods already includes KisBrush::angle() int dstWidth = maskWidth(scaleX, angle, subPixelX, subPixelY, info); int dstHeight = maskHeight(scaleY, angle, subPixelX, subPixelY, info); QPointF hotSpot = this->hotSpot(scaleX, scaleY, angle, info); // mask size and hotSpot function take the KisBrush rotation into account angle += KisBrush::angle(); // if there's coloring information, we merely change the alpha: in that case, // the dab should be big enough! if (coloringInformation) { // old bounds QRect oldBounds = dst->bounds(); // new bounds. we don't care if there is some extra memory occcupied. dst->setRect(QRect(0, 0, dstWidth, dstHeight)); if (dstWidth * dstHeight <= oldBounds.width() * oldBounds.height()) { // just clear the data in dst, memset(dst->data(), OPACITY_TRANSPARENT_U8, dstWidth * dstHeight * dst->pixelSize()); } else { // enlarge the data dst->initialize(); } } else { if (dst->data() == 0 || dst->bounds().isEmpty()) { qWarning() << "Creating a default black dab: no coloring info and no initialized paint device to mask"; dst->clear(QRect(0, 0, dstWidth, dstHeight)); } Q_ASSERT(dst->bounds().width() >= dstWidth && dst->bounds().height() >= dstHeight); } quint8* dabPointer = dst->data(); quint8* color = 0; if (coloringInformation) { if (dynamic_cast<PlainColoringInformation*>(coloringInformation)) { color = const_cast<quint8*>(coloringInformation->color()); } } double invScaleX = 1.0 / scaleX; double invScaleY = 1.0 / scaleY; double centerX = hotSpot.x() - 0.5 + subPixelX; double centerY = hotSpot.y() - 0.5 + subPixelY; d->shape->setSoftness( softnessFactor ); if (coloringInformation) { if (color && pixelSize == 4) { fillPixelOptimized_4bytes(color, dabPointer, dstWidth * dstHeight); } else if (color) { fillPixelOptimized_general(color, dabPointer, dstWidth * dstHeight, pixelSize); } else { for (int y = 0; y < dstHeight; y++) { for (int x = 0; x < dstWidth; x++) { memcpy(dabPointer, coloringInformation->color(), pixelSize); coloringInformation->nextColumn(); dabPointer += pixelSize; } coloringInformation->nextRow(); } } } MaskProcessingData data(dst, cs, d->randomness, d->density, centerX, centerY, invScaleX, invScaleY, angle); KisBrushMaskApplicatorBase *applicator = d->shape->applicator(); applicator->initializeData(&data); int jobs = d->idealThreadCountCached; if(dstHeight > 100 && jobs >= 4) { int splitter = dstHeight/jobs; QVector<QRect> rects; for(int i = 0; i < jobs - 1; i++) { rects << QRect(0, i*splitter, dstWidth, splitter); } rects << QRect(0, (jobs - 1)*splitter, dstWidth, dstHeight - (jobs - 1)*splitter); OperatorWrapper wrapper(applicator); QtConcurrent::blockingMap(rects, wrapper); } else { QRect rect(0, 0, dstWidth, dstHeight); applicator->process(rect); } }