void KisSimpleNoiseReducer::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* config, KoUpdater* progressUpdater ) const { QPoint srcTopLeft = applyRect.topLeft(); Q_ASSERT(device); int threshold, windowsize; if (config == 0) { config = defaultConfiguration(device); } if (progressUpdater) { progressUpdater->setRange(0, applyRect.width() * applyRect.height()); } int count = 0; threshold = config->getInt("threshold", 15); windowsize = config->getInt("windowsize", 1); const KoColorSpace* cs = device->colorSpace(); // Compute the blur mask KisCircleMaskGenerator* kas = new KisCircleMaskGenerator(2*windowsize + 1, 1, windowsize, windowsize, 2); KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMaskGenerator(kas); delete kas; KisPaintDeviceSP interm = new KisPaintDevice(*device); // TODO no need for a full copy and then a transaction KisConvolutionPainter painter(interm); painter.beginTransaction("bouuh"); painter.applyMatrix(kernel, interm, srcTopLeft, srcTopLeft, applyRect.size(), BORDER_REPEAT); painter.deleteTransaction(); if (progressUpdater && progressUpdater->interrupted()) { return; } KisHLineIteratorSP dstIt = device->createHLineIteratorNG(srcTopLeft.x(), srcTopLeft.y(), applyRect.width()); KisHLineConstIteratorSP intermIt = interm->createHLineConstIteratorNG(srcTopLeft.x(), srcTopLeft.y(), applyRect.width()); for (int j = 0; j < applyRect.height() && !(progressUpdater && progressUpdater->interrupted()); j++) { do { quint8 diff = cs->difference(dstIt->oldRawData(), intermIt->oldRawData()); if (diff > threshold) { memcpy(dstIt->rawData(), intermIt->oldRawData(), cs->pixelSize()); } if (progressUpdater) progressUpdater->setValue(++count); intermIt->nextPixel(); } while (dstIt->nextPixel() && !(progressUpdater && progressUpdater->interrupted())); dstIt->nextRow(); intermIt->nextRow(); } }
void KisOilPaintFilter::OilPaint(const KisPaintDeviceSP src, KisPaintDeviceSP dst, const QPoint& srcTopLeft, const QPoint& dstTopLeft, int w, int h, int BrushSize, int Smoothness, KoUpdater* progressUpdater) const { if (progressUpdater) { progressUpdater->setRange(0, w * h); } QRect bounds(srcTopLeft.x(), srcTopLeft.y(), w, h); KisHLineConstIteratorSP it = src->createHLineConstIteratorNG(srcTopLeft.x(), srcTopLeft.y(), w); KisHLineIteratorSP dstIt = dst->createHLineIteratorNG(dstTopLeft.x(), dstTopLeft.y(), w); int progress = 0; for (qint32 yOffset = 0; yOffset < h; yOffset++) { do { //&& !cancelRequested()) { MostFrequentColor(src, dstIt->rawData(), bounds, it->x(), it->y(), BrushSize, Smoothness); } while (it->nextPixel() && dstIt->nextPixel()); it->nextRow(); dstIt->nextRow(); if (progressUpdater) progressUpdater->setValue(progress += w); } }
void KisUnsharpFilter::process(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* config, KoUpdater* progressUpdater ) const { QPointer<KoUpdater> filterUpdater = 0; QPointer<KoUpdater> convolutionUpdater = 0; KoProgressUpdater* updater = 0; if (progressUpdater) { updater = new KoProgressUpdater(progressUpdater); updater->start(); // Two sub-sub tasks that each go from 0 to 100. convolutionUpdater = updater->startSubtask(); filterUpdater = updater->startSubtask(); } if (!config) config = new KisFilterConfiguration(id().id(), 1); QVariant value; uint halfSize = (config->getProperty("halfSize", value)) ? value.toUInt() : 5; uint brushsize = 2 * halfSize + 1; double amount = (config->getProperty("amount", value)) ? value.toDouble() : 0.5; uint threshold = (config->getProperty("threshold", value)) ? value.toUInt() : 10; KisCircleMaskGenerator* kas = new KisCircleMaskGenerator(brushsize, 1, halfSize, halfSize, 2); KisConvolutionKernelSP kernel = KisConvolutionKernel::fromMaskGenerator(kas); KisPaintDeviceSP interm = new KisPaintDevice(*device); const KoColorSpace * cs = interm->colorSpace(); KoConvolutionOp * convolutionOp = cs->convolutionOp(); KisConvolutionPainter painter(interm); // TODO no need for a full copy and then a transaction if (progressUpdater) { painter.setProgress(convolutionUpdater); } QBitArray channelFlags = config->channelFlags(); if (channelFlags.isEmpty()) { channelFlags = cs->channelFlags(); } painter.setChannelFlags(channelFlags); painter.beginTransaction("convolution step"); painter.applyMatrix(kernel, interm, applyRect.topLeft(), applyRect.topLeft(), applyRect.size(), BORDER_REPEAT); painter.deleteTransaction(); if (progressUpdater && progressUpdater->interrupted()) { return; } KisHLineIteratorSP dstIt = device->createHLineIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); KisHLineConstIteratorSP intermIt = interm->createHLineConstIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); int cdepth = cs -> pixelSize(); quint8 *colors[2]; colors[0] = new quint8[cdepth]; colors[1] = new quint8[cdepth]; int pixelsProcessed = 0; qreal weights[2]; qreal factor = 128; // XXX: Added static cast to avoid warning weights[0] = static_cast<qreal>(factor * (1. + amount)); weights[1] = static_cast<qreal>(-factor * amount); int steps = 100 / applyRect.width() * applyRect.height(); for (int j = 0; j < applyRect.height(); j++) { do { quint8 diff = cs->difference(dstIt->oldRawData(), intermIt->oldRawData()); if (diff > threshold) { memcpy(colors[0], dstIt->oldRawData(), cdepth); memcpy(colors[1], intermIt->oldRawData(), cdepth); convolutionOp->convolveColors(colors, weights, dstIt->rawData(), factor, 0, 2.0, channelFlags); } else { memcpy(dstIt->rawData(), dstIt->oldRawData(), cdepth); } ++pixelsProcessed; if (progressUpdater) filterUpdater->setProgress(steps * pixelsProcessed); intermIt->nextPixel(); } while (dstIt->nextPixel()); if (progressUpdater && progressUpdater->interrupted()) { return; } dstIt->nextRow(); intermIt->nextRow(); } delete colors[0]; delete colors[1]; delete updater; if (progressUpdater) progressUpdater->setProgress(100); }
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; }
KisSpacingInformation KisDuplicateOp::paintAt(const KisPaintInformation& info) { if (!painter()->device()) return 1.0; KisBrushSP brush = m_brush; if (!brush) return 1.0; if (!brush->canPaintFor(info)) return 1.0; if (!m_duplicateStartIsSet) { m_duplicateStartIsSet = true; m_duplicateStart = info.pos(); } KisPaintDeviceSP realSourceDevice = settings->node()->paintDevice(); qreal scale = m_sizeOption.apply(info); if (checkSizeTooSmall(scale)) return KisSpacingInformation(); QPointF hotSpot = brush->hotSpot(scale, scale, 0, info); QPointF pt = info.pos() - hotSpot; setCurrentScale(scale); // Split the coordinates into integer plus fractional parts. The integer // is where the dab will be positioned and the fractional part determines // the sub-pixel positioning. qint32 x, y; qreal xFraction, yFraction; // will not be used splitCoordinate(pt.x(), &x, &xFraction); splitCoordinate(pt.y(), &y, &yFraction); QPoint srcPoint; if(m_moveSourcePoint) { srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()), y - static_cast<qint32>(settings->offset().y())); } else { srcPoint = QPoint(static_cast<qint32>(settings->position().x() - hotSpot.x()), static_cast<qint32>(settings->position().y() - hotSpot.y())); } qint32 sw = brush->maskWidth(scale, 0.0, xFraction, yFraction, info); qint32 sh = brush->maskHeight(scale, 0.0, xFraction, yFraction, info); if (srcPoint.x() < 0) srcPoint.setX(0); if (srcPoint.y() < 0) srcPoint.setY(0); // Perspective correction ? KisImageWSP image = settings->m_image; if (m_perspectiveCorrection && image && image->perspectiveGrid()->countSubGrids() == 1) { Matrix3qreal startM = Matrix3qreal::Identity(); Matrix3qreal endM = Matrix3qreal::Identity(); // First look for the grid corresponding to the start point KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin(); QRect r = QRect(0, 0, image->width(), image->height()); #if 1 if (subGridStart) { startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); } #endif #if 1 // Second look for the grid corresponding to the end point KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin(); if (subGridEnd) { endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); } #endif // Compute the translation in the perspective transformation space: QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart)); QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset())); QPointF translat = duplicateStartPositionT - positionStartPaintingT; KisRectIteratorSP dstIt = m_srcdev->createRectIteratorNG(0, 0, sw, sh); KisRandomSubAccessorSP srcAcc = realSourceDevice->createRandomSubAccessor(); //Action do { QPointF p = KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt->x() + x, dstIt->y() + y)) + translat); srcAcc->moveTo(p); srcAcc->sampledOldRawData(dstIt->rawData()); } while (dstIt->nextPixel()); } else { KisPainter copyPainter(m_srcdev); copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.bitBltOldData(0, 0, realSourceDevice, srcPoint.x(), srcPoint.y(), sw, sh); copyPainter.end(); } // heal ? if (m_healing) { quint16 srcData[4]; quint16 tmpData[4]; qreal* matrix = new qreal[ 3 * sw * sh ]; // First divide const KoColorSpace* srcCs = realSourceDevice->colorSpace(); const KoColorSpace* tmpCs = m_srcdev->colorSpace(); KisHLineConstIteratorSP srcIt = realSourceDevice->createHLineConstIteratorNG(x, y, sw); KisHLineIteratorSP tmpIt = m_srcdev->createHLineIteratorNG(0, 0, sw); qreal* matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; i < sw; i++) { srcCs->toLabA16(srcIt->oldRawData(), (quint8*)srcData, 1); tmpCs->toLabA16(tmpIt->rawData(), (quint8*)tmpData, 1); // Division for (int k = 0; k < 3; k++) { matrixIt[k] = srcData[k] / (qreal)qMax((int)tmpData [k], 1); } srcIt->nextPixel(); tmpIt->nextPixel(); matrixIt += 3; } srcIt->nextRow(); tmpIt->nextRow(); } // Minimize energy { int iter = 0; qreal err; qreal* solution = new qreal [ 3 * sw * sh ]; do { err = minimizeEnergy(&matrix[0], &solution[0], sw, sh); // swap pointers qreal *tmp = matrix; matrix = solution; solution = tmp; iter++; } while (err > 0.00001 && iter < 100); delete [] solution; } // Finaly multiply KisHLineIteratorSP srcIt2 = realSourceDevice->createHLineIteratorNG(x, y, sw); KisHLineIteratorSP tmpIt2 = m_srcdev->createHLineIteratorNG(0, 0, sw); matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; i < sw; i++) { srcCs->toLabA16(srcIt2->rawData(), (quint8*)srcData, 1); tmpCs->toLabA16(tmpIt2->rawData(), (quint8*)tmpData, 1); // Multiplication for (int k = 0; k < 3; k++) { tmpData[k] = (int)CLAMP(matrixIt[k] * qMax((int) tmpData[k], 1), 0, 65535); } tmpCs->fromLabA16((quint8*)tmpData, tmpIt2->rawData(), 1); srcIt2->nextPixel(); tmpIt2->nextPixel(); matrixIt += 3; } srcIt2->nextRow(); tmpIt2->nextRow(); } delete [] matrix; } static const KoColorSpace *cs = KoColorSpaceRegistry::instance()->alpha8(); static KoColor color(Qt::black, cs); KisFixedPaintDeviceSP dab = m_dabCache->fetchDab(cs, color, scale, scale, 0.0, info); QRect dstRect = QRect(x, y, dab->bounds().width(), dab->bounds().height()); if (dstRect.isEmpty()) return 1.0; painter()->bitBltWithFixedSelection(dstRect.x(), dstRect.y(), m_srcdev, dab, dstRect.width(), dstRect.height()); painter()->renderMirrorMaskSafe(dstRect, m_srcdev, 0, 0, dab, !m_dabCache->needSeparateOriginal()); return effectiveSpacing(dstRect.width(), dstRect.height()); }
void KisFilterFastColorTransfer::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfiguration* config, KoUpdater* progressUpdater) const { Q_ASSERT(device != 0); dbgPlugins << "Start transferring color"; // Convert ref and src to LAB const KoColorSpace* labCS = KoColorSpaceRegistry::instance()->lab16(); if (!labCS) { dbgPlugins << "The LAB colorspace is not available."; return; } dbgPlugins << "convert a copy of src to lab"; const KoColorSpace* oldCS = device->colorSpace(); KisPaintDeviceSP srcLAB = new KisPaintDevice(*device.data()); dbgPlugins << "srcLab : " << srcLAB->extent(); KUndo2Command* cmd = srcLAB->convertTo(labCS, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); delete cmd; if (progressUpdater) { progressUpdater->setRange(0, 2 * applyRect.width() * applyRect.height()); } int count = 0; // Compute the means and sigmas of src dbgPlugins << "Compute the means and sigmas of src"; double meanL_src = 0., meanA_src = 0., meanB_src = 0.; double sigmaL_src = 0., sigmaA_src = 0., sigmaB_src = 0.; KisSequentialConstIterator srcIt(srcLAB, applyRect); do { const quint16* data = reinterpret_cast<const quint16*>(srcIt.oldRawData()); quint32 L = data[0]; quint32 A = data[1]; quint32 B = data[2]; meanL_src += L; meanA_src += A; meanB_src += B; sigmaL_src += L * L; sigmaA_src += A * A; sigmaB_src += B * B; if (progressUpdater) progressUpdater->setValue(++count); } while (srcIt.nextPixel() && !(progressUpdater && progressUpdater->interrupted())); double totalSize = 1. / (applyRect.width() * applyRect.height()); meanL_src *= totalSize; meanA_src *= totalSize; meanB_src *= totalSize; sigmaL_src *= totalSize; sigmaA_src *= totalSize; sigmaB_src *= totalSize; dbgPlugins << totalSize << "" << meanL_src << "" << meanA_src << "" << meanB_src << "" << sigmaL_src << "" << sigmaA_src << "" << sigmaB_src; double meanL_ref = config->getDouble("meanL"); double meanA_ref = config->getDouble("meanA"); double meanB_ref = config->getDouble("meanB"); double sigmaL_ref = config->getDouble("sigmaL"); double sigmaA_ref = config->getDouble("sigmaA"); double sigmaB_ref = config->getDouble("sigmaB"); // Transfer colors dbgPlugins << "Transfer colors"; { double coefL = sqrt((sigmaL_ref - meanL_ref * meanL_ref) / (sigmaL_src - meanL_src * meanL_src)); double coefA = sqrt((sigmaA_ref - meanA_ref * meanA_ref) / (sigmaA_src - meanA_src * meanA_src)); double coefB = sqrt((sigmaB_ref - meanB_ref * meanB_ref) / (sigmaB_src - meanB_src * meanB_src)); KisHLineConstIteratorSP srcLABIt = srcLAB->createHLineConstIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); KisHLineIteratorSP dstIt = device->createHLineIteratorNG(applyRect.x(), applyRect.y(), applyRect.width()); quint16 labPixel[4]; for (int y = 0; y < applyRect.height() && !(progressUpdater && progressUpdater->interrupted()); ++y) { do { const quint16* data = reinterpret_cast<const quint16*>(srcLABIt->oldRawData()); labPixel[0] = (quint16)CLAMP(((double)data[0] - meanL_src) * coefL + meanL_ref, 0., 65535.); labPixel[1] = (quint16)CLAMP(((double)data[1] - meanA_src) * coefA + meanA_ref, 0., 65535.); labPixel[2] = (quint16)CLAMP(((double)data[2] - meanB_src) * coefB + meanB_ref, 0., 65535.); labPixel[3] = data[3]; oldCS->fromLabA16(reinterpret_cast<const quint8*>(labPixel), dstIt->rawData(), 1); if (progressUpdater) progressUpdater->setValue(++count); srcLABIt->nextPixel(); } while(dstIt->nextPixel()); dstIt->nextRow(); srcLABIt->nextRow(); } } }