void IccTransform::transform(DImg& image, const TransformDescription& description, DImgLoaderObserver* const observer) { const int bytesDepth = image.bytesDepth(); const int pixels = image.width() * image.height(); // convert ten scanlines in a batch const int pixelsPerStep = image.width() * 10; uchar* data = image.bits(); // see dimgloader.cpp, granularity(). int granularity = 1; if (observer) { granularity = (int)((pixels / (20 * 0.9)) / observer->granularity()); } int checkPoint = pixels; // it is safe to use the same input and output buffer if the format is the same if (description.inputFormat == description.outputFormat) { for (int p = pixels; p > 0; p -= pixelsPerStep) { int pixelsThisStep = qMin(p, pixelsPerStep); int size = pixelsThisStep * bytesDepth; LcmsLock lock; dkCmsDoTransform(d->handle, data, data, pixelsThisStep); data += size; if (observer && p <= checkPoint) { checkPoint -= granularity; observer->progressInfo(&image, 0.1 + 0.9 * (1.0 - float(p) / float(pixels))); } } } else { QVarLengthArray<uchar> buffer(pixelsPerStep * bytesDepth); for (int p = pixels; p > 0; p -= pixelsPerStep) { int pixelsThisStep = qMin(p, pixelsPerStep); int size = pixelsThisStep * bytesDepth; LcmsLock lock; memcpy(buffer.data(), data, size); dkCmsDoTransform(d->handle, buffer.data(), data, pixelsThisStep); data += size; if (observer && p <= checkPoint) { checkPoint -= granularity; observer->progressInfo(&image, 0.1 + 0.9 * (1.0 - float(p) / float(pixels))); } } } }
void BorderFilter::pattern(DImg& src, DImg& dest, int borderWidth, const DColor& firstColor, const DColor& secondColor, int firstWidth, int secondWidth) { // Original image with the first solid border around. DImg tmp; solid(src, tmp, firstColor, firstWidth); // Border tiled image using pattern with second solid border around. int width, height; if (d->settings.orgWidth > d->settings.orgHeight) { height = tmp.height() + borderWidth * 2; width = (int)(height * d->orgRatio); } else { width = tmp.width() + borderWidth * 2; height = (int)(width / d->orgRatio); } DImg tmp2(width, height, tmp.sixteenBit(), tmp.hasAlpha()); qCDebug(DIGIKAM_DIMG_LOG) << "Border File:" << d->settings.borderPath; DImg border(d->settings.borderPath); if (border.isNull()) { return; } border.convertToDepthOfImage(&tmp2); for (int x = 0 ; x < width ; x += border.width()) { for (int y = 0 ; y < height ; y += border.height()) { tmp2.bitBltImage(&border, x, y); } } solid(tmp2, dest, secondColor, secondWidth); // Merge both images to one. if (d->settings.orgWidth > d->settings.orgHeight) { dest.bitBltImage(&tmp, (dest.width() - tmp.width()) / 2, borderWidth); } else { dest.bitBltImage(&tmp, borderWidth, (dest.height() - tmp.height()) / 2); } }
void BorderFilter::solid2(DImg& src, DImg& dest, const DColor& fg, int borderWidth) { dest = DImg(src.width() + borderWidth * 2, src.height() + borderWidth * 2, src.sixteenBit(), src.hasAlpha()); dest.fill(fg); dest.bitBltImage(&src, borderWidth, borderWidth); }
void LensAutoFixTool::preparePreview() { // Settings information must be get before to disable settings view. LensFunContainer settings = d->cameraSelector->settings(); d->settingsView->assignFilterSettings(settings); ImageIface* const iface = d->previewWidget->imageIface(); DImg preview = iface->preview(); if (d->showGrid->isChecked()) { QBitmap pattern(9, 9); pattern.clear(); QPainter p1(&pattern); p1.setPen(QPen(Qt::black, 1)); p1.drawLine(5, 0, 5, 9); p1.drawLine(0, 5, 9, 5); p1.end(); QPixmap pix(preview.size()); pix.fill(Qt::transparent); QPainter p2(&pix); p2.setPen(QPen(Qt::gray, 1)); p2.fillRect(0, 0, pix.width(), pix.height(), QBrush(pattern)); p2.end(); DImg grid(pix.toImage()); DColorComposer* const composer = DColorComposer::getComposer(DColorComposer::PorterDuffNone); DColorComposer::MultiplicationFlags flags = DColorComposer::NoMultiplication; // Do alpha blending of template on dest image preview.bitBlendImage(composer, &grid, 0, 0, preview.width(), preview.height(), 0, 0, flags); } setFilter(new LensFunFilter(&preview, this, settings)); }
void ContentAwareResizeTool::prepareEffect() { if (d->prevW != d->wInput->value() || d->prevH != d->hInput->value() || d->prevWP != d->wpInput->value() || d->prevHP != d->hpInput->value()) { slotValuesChanged(); } disableSettings(); ImageIface* iface = d->previewWidget->imageIface(); int w = iface->previewWidth(); int h = iface->previewHeight(); DImg imTemp = iface->getOriginalImg()->smoothScale(w, h, Qt::KeepAspectRatio); int new_w = (int)(w*d->wpInput->value()/100.0); int new_h = (int)(h*d->hpInput->value()/100.0); if (d->mixedRescaleInput->value()<100.0) // mixed rescale { double stdRescaleP = (100.0 - d->mixedRescaleInput->value()) / 100.0; int diff_w = (int)(stdRescaleP * (w - new_w)); int diff_h = (int)(stdRescaleP * (h - new_h)); imTemp.resize(imTemp.width() - diff_w, imTemp.height() - diff_h); } QImage mask; if (d->weightMaskBox->isChecked()) { mask = d->previewWidget->getMask(); } contentAwareResizeCore(&imTemp, new_w, new_h, mask); }
void ShearTool::setPreviewImage() { ImageIface* const iface = d->previewWidget->imageIface(); int w = iface->previewSize().width(); int h = iface->previewSize().height(); DImg imTemp = filter()->getTargetImage().smoothScale(w, h, Qt::KeepAspectRatio); DImg imDest( w, h, filter()->getTargetImage().sixteenBit(), filter()->getTargetImage().hasAlpha() ); imDest.fill( DColor(d->previewWidget->palette().color(QPalette::Background).rgb(), filter()->getTargetImage().sixteenBit()) ); imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); iface->setPreview(imDest.smoothScale(iface->previewSize())); d->previewWidget->updatePreview(); ShearFilter* const tool = dynamic_cast<ShearFilter*>(filter()); if (tool) { QSize newSize = tool->getNewSize(); QString temp; d->newWidthLabel->setText(temp.setNum( newSize.width()) + i18n(" px") ); d->newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") ); } }
bool UndoCache::putData(int level, const DImg& img) const { QFile file(d->cacheFile(level)); KDiskFreeSpaceInfo info = KDiskFreeSpaceInfo::freeSpaceInfo(d->cacheDir); unsigned long fspace = (unsigned long)(info.available()/1024.0/1024.0); kDebug() << "Free space available in Editor cache [" << d->cacheDir << "] in Mbytes: " << fspace; if (file.exists() || !file.open(QIODevice::WriteOnly) || fspace < 1024) // Check if free space is over 1 Gb to put data in cache. { return false; } QDataStream ds(&file); ds << img.width(); ds << img.height(); ds << img.sixteenBit(); ds << img.hasAlpha(); QByteArray ba((const char*)img.bits(), img.numBytes()); ds << ba; file.close(); d->cachedLevels << level; return true; }
void UndoManager::getSnapshot(int index, DImg* const img) const { DImg data = d->undoCache->getData(index); // Pass ownership of buffer. If data is null, img will be null img->putImageData(data.width(), data.height(), data.sixteenBit(), data.hasAlpha(), data.bits(), true); }
void BorderFilter::solid(DImg& src, DImg& dest, const DColor& fg, int borderWidth) { if (d->settings.orgWidth > d->settings.orgHeight) { int height = src.height() + borderWidth * 2; dest = DImg((int)(height * d->orgRatio), height, src.sixteenBit(), src.hasAlpha()); dest.fill(fg); dest.bitBltImage(&src, (dest.width() - src.width()) / 2, borderWidth); } else { int width = src.width() + borderWidth * 2; dest = DImg(width, (int)(width / d->orgRatio), src.sixteenBit(), src.hasAlpha()); dest.fill(fg); dest.bitBltImage(&src, borderWidth, (dest.height() - src.height()) / 2); } }
void BCGFilter::applyBCG(DImg& image) { if (image.isNull()) { return; } applyBCG(image.bits(), image.width(), image.height(), image.sixteenBit()); }
void ResizeTool::putFinalData() { ImageIface iface(0, 0); DImg targetImage = filter()->getTargetImage(); iface.putOriginalImage(i18n("Resize"), filter()->filterAction(), targetImage.bits(), targetImage.width(), targetImage.height()); }
void RawImport::setPreviewImage() { // Preserve metadata from loaded image, and take post-processed image data d->postProcessedImage = d->previewWidget->demosaicedImage().copyMetaData(); DImg data = filter()->getTargetImage(); d->postProcessedImage.putImageData(data.width(), data.height(), data.sixteenBit(), data.hasAlpha(), data.stripImageData(), false); d->previewWidget->setPostProcessedImage(d->postProcessedImage); d->settingsBox->setPostProcessedImage(d->postProcessedImage); EditorToolIface::editorToolIface()->setToolStopProgress(); setBusy(false); }
uchar* ImageIface::Private::previewImageData() { if (previewImage.isNull()) { DImg* im = 0; if (previewType == FullImage) { im = core->getImg(); if (!im || im->isNull()) { return 0; } } else // ImageSelection { im = new DImg(core->getImgSelection()); if (!im) { return 0; } if (im->isNull()) { delete im; return 0; } im->setIccProfile(core->getEmbeddedICC()); } QSize sz(im->width(), im->height()); sz.scale(constrainWidth, constrainHeight, Qt::KeepAspectRatio); previewImage = im->smoothScale(sz.width(), sz.height()); previewWidth = previewImage.width(); previewHeight = previewImage.height(); // only create another copy if needed, in setPreviewImage targetPreviewImage = previewImage; if (previewType == ImageSelection) { delete im; } } DImg previewData = previewImage.copyImageData(); return previewData.stripImageData(); }
void BorderFilter::bevel2(DImg& src, DImg& dest, const DColor& topColor, const DColor& btmColor, int borderWidth) { int x, y; int wc; dest = DImg(src.width() + borderWidth * 2, src.height() + borderWidth * 2, src.sixteenBit(), src.hasAlpha()); // top for (y = 0, wc = (int)dest.width() - 1; y < borderWidth; ++y, --wc) { for (x = 0; x < wc; ++x) { dest.setPixelColor(x, y, topColor); } for (; x < (int)dest.width(); ++x) { dest.setPixelColor(x, y, btmColor); } } // left and right for (; y < (int)dest.height() - borderWidth; ++y) { for (x = 0; x < borderWidth; ++x) { dest.setPixelColor(x, y, topColor); } for (x = (int)dest.width() - 1; x > (int)dest.width() - borderWidth - 1; --x) { dest.setPixelColor(x, y, btmColor); } } // bottom for (wc = borderWidth; y < (int)dest.height(); ++y, --wc) { for (x = 0; x < wc; ++x) { dest.setPixelColor(x, y, topColor); } for (; x < (int)dest.width(); ++x) { dest.setPixelColor(x, y, btmColor); } } dest.bitBltImage(&src, borderWidth, borderWidth); }
void ResizeTool::putPreviewData() { ImageIface* iface = d->previewWidget->imageIface(); int w = iface->previewWidth(); int h = iface->previewHeight(); DImg imTemp = filter()->getTargetImage().smoothScale(w, h, Qt::KeepAspectRatio); DImg imDest(w, h, filter()->getTargetImage().sixteenBit(), filter()->getTargetImage().hasAlpha()); QColor background = toolView()->backgroundRole(); imDest.fill(DColor(background, filter()->getTargetImage().sixteenBit())); imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2); iface->putPreviewImage((imDest.smoothScale(iface->previewWidth(), iface->previewHeight())).bits()); d->previewWidget->updatePreview(); }
void BorderFilter::pattern2(DImg& src, DImg& dest, int borderWidth, const DColor& firstColor, const DColor& secondColor, int firstWidth, int secondWidth) { // Border tile. int w = d->settings.orgWidth + borderWidth * 2; int h = d->settings.orgHeight + borderWidth * 2; qCDebug(DIGIKAM_DIMG_LOG) << "Border File:" << d->settings.borderPath; DImg border(d->settings.borderPath); if (border.isNull()) { return; } DImg borderImg(w, h, src.sixteenBit(), src.hasAlpha()); border.convertToDepthOfImage(&borderImg); for (int x = 0 ; x < w ; x += border.width()) { for (int y = 0 ; y < h ; y += border.height()) { borderImg.bitBltImage(&border, x, y); } } // First line around the pattern tile. DImg tmp = borderImg.smoothScale(src.width() + borderWidth * 2, src.height() + borderWidth * 2); solid2(tmp, dest, firstColor, firstWidth); // Second line around original image. tmp.reset(); solid2(src, tmp, secondColor, secondWidth); // Copy original image. dest.bitBltImage(&tmp, borderWidth, borderWidth); }
SharpenFilter::SharpenFilter(DImgThreadedFilter* const parentFilter, const DImg& orgImage, const DImg& destImage, int progressBegin, int progressEnd, double radius, double sigma) : DImgThreadedFilter(parentFilter, orgImage, destImage, progressBegin, progressEnd, parentFilter->filterName() + QLatin1String(": Sharpen")) { m_radius = radius; m_sigma = sigma; // We need to provide support for orgImage == destImage. // The algorithm does not support this out of the box, so use a temporary. if (orgImage.bits() == destImage.bits()) { m_destImage = DImg(destImage.width(), destImage.height(), destImage.sixteenBit()); } filterImage(); if (orgImage.bits() == destImage.bits()) { memcpy(destImage.bits(), m_destImage.bits(), m_destImage.numBytes()); } }
void BorderFilter::Private::setup(const DImg& m_orgImage) { solidColor = DColor(settings.solidColor, m_orgImage.sixteenBit()); niepceBorderColor = DColor(settings.niepceBorderColor, m_orgImage.sixteenBit()); niepceLineColor = DColor(settings.niepceLineColor, m_orgImage.sixteenBit()); bevelUpperLeftColor = DColor(settings.bevelUpperLeftColor, m_orgImage.sixteenBit()); bevelLowerRightColor = DColor(settings.bevelLowerRightColor, m_orgImage.sixteenBit()); decorativeFirstColor = DColor(settings.decorativeFirstColor, m_orgImage.sixteenBit()); decorativeSecondColor = DColor(settings.decorativeSecondColor, m_orgImage.sixteenBit()); if (settings.preserveAspectRatio) { orgRatio = (float)settings.orgWidth / (float)settings.orgHeight; int size = qMin(m_orgImage.height(), m_orgImage.width()); borderMainWidth = (int)(size * settings.borderPercent); border2ndWidth = (int)(size * 0.005); // Clamp internal border with to 1 pixel to be visible with small image. if (border2ndWidth < 1) { border2ndWidth = 1; } } }
void RawSettingsBox::setPostProcessedImage(DImg& img) { histogramBox()->histogram()->stopHistogramComputation(); histogramBox()->histogram()->updateData(img.bits(), img.width(), img.height(), img.sixteenBit()); }
void BorderFilter::bevel(DImg& src, DImg& dest, const DColor& topColor, const DColor& btmColor, int borderWidth) { int width, height; if (d->settings.orgWidth > d->settings.orgHeight) { height = src.height() + borderWidth * 2; width = (int)(height * d->orgRatio); } else { width = src.width() + borderWidth * 2; height = (int)(width / d->orgRatio); } dest = DImg(width, height, src.sixteenBit(), src.hasAlpha()); dest.fill(topColor); QPolygon btTriangle(3); btTriangle.setPoint(0, width, 0); btTriangle.setPoint(1, 0, height); btTriangle.setPoint(2, width, height); QRegion btRegion(btTriangle); // paint upper right corner QPoint upperRightCorner((width - ((width - src.width()) / 2) - 2), ((0 + (height - src.height())) / 2 + 2) ); for (int x = upperRightCorner.x(); x < width; ++x) { for (int y = 0; y < upperRightCorner.y(); ++y) { if (btRegion.contains(QPoint(x, y))) { dest.setPixelColor(x, y, btmColor); } } } // paint right border for (int x = upperRightCorner.x(); x < width; ++x) { for (int y = upperRightCorner.y(); y < height; ++y) { dest.setPixelColor(x, y, btmColor); } } // paint lower left corner QPoint lowerLeftCorner((0 + ((width - src.width()) / 2) + 2), (height - ((height - src.height()) / 2) - 2) ); for (int x = 0; x < lowerLeftCorner.x(); ++x) { for (int y = lowerLeftCorner.y(); y < height; ++y) { if (btRegion.contains(QPoint(x, y))) { dest.setPixelColor(x, y, btmColor); } } } // paint bottom border for (int x = lowerLeftCorner.x(); x < width; ++x) { for (int y = lowerLeftCorner.y(); y < height; ++y) { dest.setPixelColor(x, y, btmColor); } } if (d->settings.orgWidth > d->settings.orgHeight) { dest.bitBltImage(&src, (dest.width() - src.width()) / 2, borderWidth); } else { dest.bitBltImage(&src, borderWidth, (dest.height() - src.height()) / 2); } }
void RawSettingsBox::setDemosaicedImage(DImg& img) { d->curveWidget->stopHistogramComputation(); d->curveWidget->updateData(img.bits(), img.width(), img.height(), img.sixteenBit()); }
bool WaterMark::toolOperations() { if (!loadToDImg()) { return false; } QString fileName = settings()[QLatin1String("Watermark image")].toString(); int placement = settings()[QLatin1String("Placement")].toInt(); int size = settings()[QLatin1String("Watermark size")].toInt(); int xMargin = settings()[QLatin1String("X margin")].toInt(); int yMargin = settings()[QLatin1String("Y margin")].toInt(); bool useImage = settings()[QLatin1String("Use image")].toBool(); QString text = settings()[QLatin1String("Text")].toString(); QFont font = settings()[QLatin1String("Font")].toString(); QColor fontColor = settings()[QLatin1String("Color")].toString(); int textOpacity = settings()[QLatin1String("Text opacity")].toInt(); bool useBackground = settings()[QLatin1String("Use background")].toBool(); QColor backgroundColor = settings()[QLatin1String("Background color")].toString(); int backgroundOpacity = settings()[QLatin1String("Background opacity")].toInt(); DImg watermarkImage; DColorComposer* composer = DColorComposer::getComposer(DColorComposer::PorterDuffNone); int marginW = lround(image().width() * (xMargin / 100.0)); int marginH = lround(image().height() * (yMargin / 100.0)); if (useImage) { watermarkImage = DImg(fileName); if (watermarkImage.isNull()) { return false; } DImg tempImage = watermarkImage.smoothScale(image().width() * size / 100, image().height() * size / 100, Qt::KeepAspectRatio); watermarkImage = tempImage; } else { int alignMode; const int radius = 10; if (text.isEmpty()) { return false; } int fontSize = queryFontSize(text, font, size); if (fontSize == 0) { return false; } switch (placement) { case Private::TopLeft: alignMode = Qt::AlignLeft; break; case Private::TopRight: alignMode = Qt::AlignRight; break; case Private::BottomLeft: alignMode = Qt::AlignLeft; break; case Private::Center: alignMode = Qt::AlignCenter; break; default : // BottomRight alignMode = Qt::AlignRight; break; } font.setPointSizeF(fontSize); QFontMetrics fontMt(font); QRect fontRect = fontMt.boundingRect(radius, radius, image().width(), image().height(), 0, text); // Add a transparent layer. QRect backgroundRect(fontRect.x() - radius, fontRect.y() - radius, fontRect.width() + 2 * radius, fontRect.height() + 2 * radius); DImg backgroundLayer(backgroundRect.width(), backgroundRect.height(), image().sixteenBit(), true); DColor transparent(QColor(0, 0, 0)); transparent.setAlpha(0); if (image().sixteenBit()) { transparent.convertToSixteenBit(); } backgroundLayer.fill(transparent); DImg grayTransLayer(fontRect.width(), fontRect.height(), image().sixteenBit(), true); if (useBackground) { DColor grayTrans(backgroundColor); grayTrans.setAlpha(backgroundOpacity * 255 / 100); if (image().sixteenBit()) { grayTrans.convertToSixteenBit(); } grayTransLayer.fill(grayTrans); backgroundLayer.bitBlendImage(composer, &grayTransLayer, 0, 0, grayTransLayer.width(), grayTransLayer.height(), radius, radius); } BlurFilter blur(&backgroundLayer, 0L, radius); blur.startFilterDirectly(); backgroundLayer.putImageData(blur.getTargetImage().bits()); // Draw text QImage img = backgroundLayer.copyQImage(fontRect); QPainter p(&img); fontColor.setAlpha(textOpacity * 255 / 100); p.setPen(QPen(fontColor, 1)); p.setFont(font); p.save(); p.drawText(0, 0, fontRect.width(), fontRect.height(), alignMode, text); p.restore(); p.end(); watermarkImage = DImg(img); } watermarkImage.convertToDepthOfImage(&image()); QRect watermarkRect(0, 0, watermarkImage.width(), watermarkImage.height()); switch (placement) { case Private::TopLeft: watermarkRect.moveTopLeft(QPoint(marginW, marginH)); break; case Private::TopRight: watermarkRect.moveTopRight(QPoint(image().width() - marginW, marginH)); break; case Private::BottomLeft: watermarkRect.moveBottomLeft(QPoint(marginW, image().height() - marginH)); break; case Private::Center: watermarkRect.moveCenter(QPoint((int)(image().width() / 2), (int)(image().height() / 2))); break; default : // BottomRight watermarkRect.moveBottomRight(QPoint(image().width() - marginW, image().height() - marginH)); break; } // TODO: Create watermark filter, move code there, implement FilterAction image().bitBlendImage(composer, &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(), watermarkRect.left(), watermarkRect.top()); delete composer; return (savefromDImg()); }
bool UndoManager::putImageDataAndHistory(DImg* const img, int stepsBack) const { if (stepsBack <= 0 || stepsBack > d->undoActions.size()) { return false; } /* * We need to find a snapshot, for the state the given number of steps back. * 0 steps back is the current state of the EditorCore. * 1 step back is the snapshot of the last undo action, at d->undoActions.size() - 1. * The next problem is that if the corresponding action is reversible, * we do not have a snapshot, but need to walk forward to the first snapshot (or current * state), then apply the reversible steps. */ int step = d->undoActions.size() - stepsBack; int snapshot; for (snapshot = step; snapshot < d->undoActions.size(); ++snapshot) { if (dynamic_cast<UndoActionIrreversible*>(d->undoActions.at(snapshot))) { break; } } if (snapshot == step) { getSnapshot(step, img); } else { DImg reverting; // Get closest available snapshot if (snapshot < d->undoActions.size()) { getSnapshot(snapshot, &reverting); } else { reverting = d->core->getImg()->copyImageData(); } // revert reversible actions, until reaching desired step for (; snapshot > step; snapshot--) { UndoActionReversible* const reversible = dynamic_cast<UndoActionReversible*>(d->undoActions.at(snapshot - 1)); if (!reversible) // would be a bug { continue; } reversible->getReverseFilter().apply(reverting); } img->putImageData(reverting.width(), reverting.height(), reverting.sixteenBit(), reverting.hasAlpha(), reverting.stripImageData(), false); } // adjust history UndoAction* const action = d->undoActions.at(step); UndoMetadataContainer dataBeforeStep = action->getMetadata(); dataBeforeStep.toImage(*img); return true; }