diff --git a/libs/image/kis_filter_strategy.cc b/libs/image/kis_filter_strategy.cc index 8a6d695a13..305b93b3d8 100644 --- a/libs/image/kis_filter_strategy.cc +++ b/libs/image/kis_filter_strategy.cc @@ -1,289 +1,284 @@ /* * Copyright (c) 2004 Michael Thaler * Copyright (c) 2005 C. Boemann * Copyright (c) 2013 Juan Palacios * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_filter_strategy.h" #include #include #include #include "kis_debug.h" #include #include Q_GLOBAL_STATIC(KisFilterStrategyRegistry, s_instance) qreal KisHermiteFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ if (t < 0.0) t = -t; if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); return(0.0); } qint32 KisHermiteFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { t = (2 * t - 3 * 256) * t * t + (256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } return(0); } qint32 KisBicubicFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); /* f(t) = 1.5|t|^3 - 2.5|t|^2 + 1, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { t = (3 * t - 5 * 256) * t * t / 2 + (256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } if (t < 512) { /* f(t) = -0.5|t|^3 + 2.5|t|^2 + 4|t| - 2, -2 <= t <= 2 */ t = ((-t + 5 * 256) * t / 2 - 4 * 256 * 256) * t + (2 * 256 << 16); //go from .24 fixed point to .8 fixedpoint (hack only works with positive numbers, which it is) t = (t + 0x8000) >> 16; // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; if (t >= 128) return t - 1; return t; } return(0); } qreal KisBoxFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { if ((t >= -0.5 * weightsPositionScale) && (t < 0.5 * weightsPositionScale)) return(1.0); return(0.0); } qint32 KisBoxFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const { /* f(t) = 1, -0.5 < t <= 0.5 */ if ((t >= -128 * weightsPositionScale) && (t < 128 * weightsPositionScale)) return 255; return 0; } qreal KisBoxFilterStrategy::support(qreal weightsPositionScale) { return supportVal*weightsPositionScale; } qint32 KisBoxFilterStrategy::intSupport(qreal weightsPositionScale) { return qCeil(intSupportVal*weightsPositionScale); } qreal KisBilinearFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); if (t < 0.0) t = -t; if (t < 1.0) return(1.0 - t); return(0.0); } qint32 KisBilinearFilterStrategy::intValueAt(qint32 t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); /* f(t) = |t|, -1 <= t <= 1 */ if (t < 0) t = -t; if (t < 256) { // calc 256-1 but also go from .8 fixed point to 8bitscale. ie t = (t*255)/256; ie: if(t>=128) return t-1; if (t >= 128) return 256 - t; return 255 - t; } return(0); } qreal KisBellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); if (t < 0) t = -t; if (t < .5) return(.75 - (t * t)); if (t < 1.5) { t = (t - 1.5); return(.5 *(t * t)); } return(0.0); } qreal KisBSplineFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); qreal tt; if (t < 0) t = -t; if (t < 1) { tt = t * t; return((.5 * tt * t) - tt + (2.0 / 3.0)); } else if (t < 2) { t = 2 - t; return((1.0 / 6.0) *(t * t * t)); } return(0.0); } qreal KisLanczos3FilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); if (t < 0) t = -t; if (t < 3.0) return(sinc(t) * sinc(t / 3.0)); return(0.0); } qreal KisLanczos3FilterStrategy::sinc(qreal x) const { const qreal pi = 3.1415926535897932385; x *= pi; if (x != 0) return(sin(x) / x); return(1.0); } qreal KisMitchellFilterStrategy::valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(weightsPositionScale); const qreal B = 1.0 / 3.0; const qreal C = 1.0 / 3.0; qreal tt; tt = t * t; if (t < 0) t = -t; if (t < 1.0) { t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B)); return(t / 6.0); } else if (t < 2.0) { t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C)); return(t / 6.0); } return(0.0); } KisFilterStrategyRegistry::KisFilterStrategyRegistry() { } KisFilterStrategyRegistry::~KisFilterStrategyRegistry() { Q_FOREACH (const QString &id, keys()) { delete get(id); } dbgRegistry << "deleting KisFilterStrategyRegistry"; } KisFilterStrategyRegistry* KisFilterStrategyRegistry::instance() { if (!s_instance.exists()) { + s_instance->add(new KisAutoFilterStrategy); + s_instance->add(new KisBoxFilterStrategy); s_instance->addAlias("Box", "NearestNeighbor"); - s_instance->add(new KisHermiteFilterStrategy); s_instance->add(new KisBicubicFilterStrategy); s_instance->add(new KisBilinearFilterStrategy); s_instance->add(new KisBellFilterStrategy); s_instance->add(new KisBSplineFilterStrategy); + s_instance->add(new KisHermiteFilterStrategy); s_instance->add(new KisLanczos3FilterStrategy); s_instance->add(new KisMitchellFilterStrategy); - - s_instance->add(new KisAutoFilterStrategy); } return s_instance; } QList KisFilterStrategyRegistry::listKeys() const { QList answer; Q_FOREACH (const QString key, keys()) { answer.append(KoID(key, get(key)->name())); } return answer; } QString KisFilterStrategyRegistry::formattedDescriptions() const { QString formatedDescription(""); Q_FOREACH (const QString key, keys()) { KisFilterStrategy *strategy = get(key); QString description = strategy->description(); if (!description.isEmpty()) { formatedDescription.append("

"); formatedDescription.append(strategy->name()); formatedDescription.append(": "); formatedDescription.append(description); formatedDescription.append("

"); } } formatedDescription.append(""); return formatedDescription; } KisFilterStrategy *KisFilterStrategyRegistry::getAppropriateFilterStrategy(QSize originalSize, QSize desiredSize) const { // Default to nearest neighbor scaling for tiny source images. (i.e: individual icons or sprites) const int pixelArtThreshold = 128; if (originalSize.width() <= pixelArtThreshold || originalSize.height() <= pixelArtThreshold) { - qDebug() << "Scaling pixel art? Using nearest neighbor scaling!"; return KisFilterStrategyRegistry::instance()->value("NearestNeighbor"); } const float xScaleFactor = (float)desiredSize.width() / originalSize.width(); const float yScaleFactor = (float)desiredSize.height() / originalSize.height(); - qDebug() << ppVar(xScaleFactor) << ppVar(yScaleFactor); - if (xScaleFactor > 1.f || yScaleFactor > 1.f) { // Enlargement. - qDebug() << "Enlarging? Using bilinear filtering!"; - return KisFilterStrategyRegistry::instance()->value("Bilinear"); - } else if (xScaleFactor < 1.f || yScaleFactor < 1.f) { // Reduction. - qDebug() << "Reducing? Using bicubic filtering!"; return KisFilterStrategyRegistry::instance()->value("Bicubic"); + } else if (xScaleFactor < 1.f || yScaleFactor < 1.f) { // Reduction. + return KisFilterStrategyRegistry::instance()->value("Hermite"); } - return KisFilterStrategyRegistry::instance()->value("Bicubic"); + return KisFilterStrategyRegistry::instance()->value("NearestNeighbor"); } diff --git a/plugins/extensions/imagesize/dlg_imagesize.cc b/plugins/extensions/imagesize/dlg_imagesize.cc index 0c4a82fc7b..b3bf208726 100644 --- a/plugins/extensions/imagesize/dlg_imagesize.cc +++ b/plugins/extensions/imagesize/dlg_imagesize.cc @@ -1,437 +1,464 @@ /* * dlg_imagesize.cc - part of KimageShop^WKrayon^WKrita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2009 C. Boemann * Copyright (c) 2013 Juan Palacios * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dlg_imagesize.h" #include #include #include #include #include #include #include "kis_aspect_ratio_locker.h" #include "kis_acyclic_signal_connector.h" #include "kis_signals_blocker.h" #include "kis_double_parse_unit_spin_box.h" #include "kis_document_aware_spin_box_unit_manager.h" static const int maxImagePixelSize = 100000000; static const QString pixelStr(KoUnit::unitDescription(KoUnit::Pixel)); static const QString percentStr(i18n("Percent (%)")); static const QString pixelsInchStr(i18n("Pixels/Inch")); static const QString pixelsCentimeterStr(i18n("Pixels/Centimeter")); const QString DlgImageSize::PARAM_PREFIX = "imagesizedlg"; const QString DlgImageSize::PARAM_IMSIZE_UNIT = DlgImageSize::PARAM_PREFIX + "_imsizeunit"; const QString DlgImageSize::PARAM_SIZE_UNIT = DlgImageSize::PARAM_PREFIX + "_sizeunit"; const QString DlgImageSize::PARAM_RES_UNIT = DlgImageSize::PARAM_PREFIX + "_resunit"; const QString DlgImageSize::PARAM_RATIO_LOCK = DlgImageSize::PARAM_PREFIX + "_ratioLock"; const QString DlgImageSize::PARAM_PRINT_SIZE_SEPARATE = DlgImageSize::PARAM_PREFIX + "_printSizeSeparatly"; DlgImageSize::DlgImageSize(QWidget *parent, int width, int height, double resolution) - : KoDialog(parent) + : KoDialog(parent), + autoScaleFilter(nullptr) { setCaption(i18n("Scale To New Size")); setButtons(Ok | Cancel); setDefaultButton(Ok); // Store original size at moment of dialog creation for automatic filter selection. originalSize.setWidth(width); originalSize.setHeight(height); m_page = new WdgImageSize(this); Q_CHECK_PTR(m_page); m_page->layout()->setMargin(0); m_page->setObjectName("image_size"); m_page->pixelFilterCmb->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); m_page->pixelFilterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formattedDescriptions()); - m_page->pixelFilterCmb->setCurrent("Auto"); + m_page->pixelFilterCmb->setCurrent(i18n("Auto")); /** * Initialize Pixel Width and Height fields */ m_widthUnitManager = new KisDocumentAwareSpinBoxUnitManager(this); m_heightUnitManager = new KisDocumentAwareSpinBoxUnitManager(this, KisDocumentAwareSpinBoxUnitManager::PIX_DIR_Y); KisConfig cfg(true); /// configure the unit to image length, default unit is pixel and printing units are forbidden. m_widthUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH); m_heightUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH); m_widthUnitManager->syncWithOtherUnitManager(m_heightUnitManager); //sync the two managers, so that the units will be the same, but each manager will know a different reference for percents. m_widthUnitManager->setApparentUnitFromSymbol("px"); //set unit to pixel. m_page->pixelWidthDouble->setUnitManager(m_widthUnitManager); m_page->pixelHeightDouble->setUnitManager(m_heightUnitManager); m_page->pixelWidthDouble->setMaximum(maxImagePixelSize); m_page->pixelHeightDouble->setMaximum(maxImagePixelSize); m_page->pixelWidthDouble->changeValue(width); m_page->pixelHeightDouble->changeValue(height); m_page->pixelWidthDouble->setDisplayUnit(false); m_page->pixelHeightDouble->setDisplayUnit(false); /// add custom units int unitId = m_widthUnitManager->getApparentUnitId(); m_page->pixelSizeUnit->setModel(m_widthUnitManager); m_page->pixelSizeUnit->setCurrentIndex(unitId); /** * Connect Pixel Unit switching controls */ KisAcyclicSignalConnector *pixelUnitConnector = new KisAcyclicSignalConnector(this); pixelUnitConnector->connectForwardInt(m_page->pixelSizeUnit, SIGNAL(currentIndexChanged(int)), m_widthUnitManager, SLOT(selectApparentUnitFromIndex(int))); pixelUnitConnector->connectBackwardInt(m_widthUnitManager, SIGNAL(unitChanged(int)), m_page->pixelSizeUnit, SLOT(setCurrentIndex(int))); QString imSizeUnit = cfg.readEntry(PARAM_IMSIZE_UNIT, "px"); m_widthUnitManager->setApparentUnitFromSymbol(imSizeUnit); /** * Initialize Print Width, Height and Resolution fields */ - m_printSizeUnitManager = new KisSpinBoxUnitManager(this); m_page->printWidth->setUnitManager(m_printSizeUnitManager); m_page->printHeight->setUnitManager(m_printSizeUnitManager); m_page->printWidth->setDecimals(2); m_page->printHeight->setDecimals(2); m_page->printWidth->setDisplayUnit(false); m_page->printHeight->setDisplayUnit(false); m_page->printResolution->setDecimals(2); m_page->printResolution->setAlignment(Qt::AlignRight); m_page->printWidthUnit->setModel(m_printSizeUnitManager); //TODO: create a resolution dimension in the unit manager. m_page->printResolutionUnit->addItem(pixelsInchStr); m_page->printResolutionUnit->addItem(pixelsCentimeterStr); /** * Initialize labels and layout */ KisSizeGroup *labelsGroup = new KisSizeGroup(this); labelsGroup->addWidget(m_page->lblPixelWidth); labelsGroup->addWidget(m_page->lblPixelHeight); labelsGroup->addWidget(m_page->lblPixelFilter); labelsGroup->addWidget(m_page->lblPrintWidth); labelsGroup->addWidget(m_page->lblPrintHeight); labelsGroup->addWidget(m_page->lblResolution); KisSizeGroup *spinboxesGroup = new KisSizeGroup(this); spinboxesGroup->addWidget(m_page->pixelWidthDouble); spinboxesGroup->addWidget(m_page->pixelHeightDouble); spinboxesGroup->addWidget(m_page->printWidth); spinboxesGroup->addWidget(m_page->printHeight); spinboxesGroup->addWidget(m_page->printResolution); KisSizeGroup *comboboxesGroup = new KisSizeGroup(this); comboboxesGroup->addWidget(m_page->pixelSizeUnit); comboboxesGroup->addWidget(m_page->printWidthUnit); comboboxesGroup->addWidget(m_page->printResolutionUnit); connect(this, SIGNAL(okClicked()), this, SLOT(accept())); /** * Initialize aspect ratio buttons and lockers */ - m_page->pixelAspectRatioBtn->setKeepAspectRatio(true); m_page->printAspectRatioBtn->setKeepAspectRatio(true); m_page->constrainProportionsCkb->setChecked(true); m_pixelSizeLocker = new KisAspectRatioLocker(this); m_pixelSizeLocker->connectSpinBoxes(m_page->pixelWidthDouble, m_page->pixelHeightDouble, m_page->pixelAspectRatioBtn); m_printSizeLocker = new KisAspectRatioLocker(this); m_printSizeLocker->connectSpinBoxes(m_page->printWidth, m_page->printHeight, m_page->printAspectRatioBtn); /** * Connect Keep Aspect Lock buttons */ - KisAcyclicSignalConnector *constrainsConnector = new KisAcyclicSignalConnector(this); constrainsConnector->connectBackwardBool( m_page->constrainProportionsCkb, SIGNAL(toggled(bool)), this, SLOT(slotLockAllRatioSwitched(bool))); constrainsConnector->connectForwardBool( m_pixelSizeLocker, SIGNAL(aspectButtonToggled(bool)), this, SLOT(slotLockPixelRatioSwitched(bool))); constrainsConnector->createCoordinatedConnector()->connectBackwardBool( m_printSizeLocker, SIGNAL(aspectButtonToggled(bool)), this, SLOT(slotLockPrintRatioSwitched(bool))); constrainsConnector->createCoordinatedConnector()->connectBackwardBool( m_page->adjustPrintSizeSeparatelyCkb, SIGNAL(toggled(bool)), this, SLOT(slotAdjustSeparatelySwitched(bool))); /** * Connect Print Unit switching controls */ - KisAcyclicSignalConnector *printUnitConnector = new KisAcyclicSignalConnector(this); printUnitConnector->connectForwardInt( m_page->printWidthUnit, SIGNAL(currentIndexChanged(int)), m_printSizeUnitManager, SLOT(selectApparentUnitFromIndex(int))); printUnitConnector->connectBackwardInt( m_printSizeUnitManager, SIGNAL(unitChanged(int)), m_page->printWidthUnit, SLOT(setCurrentIndex(int))); /// connect resolution connect(m_page->printResolutionUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPrintResolutionUnitChanged())); /** * Create syncing connections between Pixel and Print values */ KisAcyclicSignalConnector *syncConnector = new KisAcyclicSignalConnector(this); syncConnector->connectForwardVoid( m_pixelSizeLocker, SIGNAL(sliderValueChanged()), this, SLOT(slotSyncPixelToPrintSize())); syncConnector->connectBackwardVoid( m_printSizeLocker, SIGNAL(sliderValueChanged()), this, SLOT(slotSyncPrintToPixelSize())); syncConnector->createCoordinatedConnector()->connectBackwardVoid( m_page->printResolution, SIGNAL(valueChanged(double)), this, SLOT(slotPrintResolutionChanged())); /** * Initialize printing values from the predefined image values */ QString printSizeUnit; if (QLocale().measurementSystem() == QLocale::MetricSystem) { printSizeUnit = "cm"; } else { // Imperial printSizeUnit = "in"; } printSizeUnit = cfg.readEntry(PARAM_SIZE_UNIT, printSizeUnit); m_printSizeUnitManager->setApparentUnitFromSymbol(printSizeUnit); setCurrentResolutionPPI(resolution); slotSyncPixelToPrintSize(); /** * Initialize aspect ratio lockers with the current proportion. */ m_pixelSizeLocker->updateAspect(); m_printSizeLocker->updateAspect(); QString printResUnit = cfg.readEntry(PARAM_RES_UNIT, ""); m_page->printResolutionUnit->setCurrentText(printResUnit); m_page->constrainProportionsCkb->setChecked(cfg.readEntry(PARAM_RATIO_LOCK, true)); m_page->adjustPrintSizeSeparatelyCkb->setChecked(cfg.readEntry(PARAM_PRINT_SIZE_SEPARATE, false)); setMainWidget(m_page); + + /** + * Set up connections for autoscale. + */ + connect(m_page->pixelWidthDouble, SIGNAL(valueChanged(double)), this, SLOT(updateAutoScaleFilter())); + connect(m_page->pixelHeightDouble, SIGNAL(valueChanged(double)), this, SLOT(updateAutoScaleFilter())); } DlgImageSize::~DlgImageSize() { KisConfig cfg(false); cfg.writeEntry(PARAM_PRINT_SIZE_SEPARATE, m_page->adjustPrintSizeSeparatelyCkb->isChecked()); cfg.writeEntry(PARAM_RATIO_LOCK, m_page->constrainProportionsCkb->isChecked()); cfg.writeEntry(PARAM_IMSIZE_UNIT, m_widthUnitManager->getApparentUnitSymbol()); cfg.writeEntry(PARAM_SIZE_UNIT, m_printSizeUnitManager->getApparentUnitSymbol()); cfg.writeEntry(PARAM_RES_UNIT, m_page->printResolutionUnit->currentText()); delete m_page; } qint32 DlgImageSize::width() { return int(m_page->pixelWidthDouble->value()); } qint32 DlgImageSize::height() { return int(m_page->pixelHeightDouble->value()); } double DlgImageSize::resolution() { return currentResolutionPPI(); } -KisFilterStrategy *DlgImageSize::filterType() +/* + * Returns the proper filter strategy based combobox state. + */ +KisFilterStrategy *DlgImageSize::getFilterStrategy() { + QSize newSize = QSize(width(), height()); + if (newSize == originalSize) return nullptr; + KoID filterID = m_page->pixelFilterCmb->currentItem(); KisFilterStrategy *filter; if (filterID.id() == "Auto") { - filter = KisFilterStrategyRegistry::instance()->getAppropriateFilterStrategy(originalSize, QSize(width(), height())); + filter = autoScaleFilter; } else { filter = KisFilterStrategyRegistry::instance()->value(filterID.id()); } return filter; } void DlgImageSize::slotSyncPrintToPixelSize() { const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked(); if (!printIsSeparate) { KisSignalsBlocker b(m_page->pixelWidthDouble, m_page->pixelHeightDouble); m_page->pixelWidthDouble->changeValue(m_page->printWidth->value() * currentResolutionPPI()); m_page->pixelHeightDouble->changeValue(m_page->printHeight->value() * currentResolutionPPI()); } else if (m_page->pixelWidthDouble->value() != 0.0) { const qreal resolution = qMax(0.001, m_page->pixelWidthDouble->value() / m_page->printWidth->value()); setCurrentResolutionPPI(resolution); } + + updateAutoScaleFilter(); } void DlgImageSize::slotSyncPixelToPrintSize() { const qreal resolution = currentResolutionPPI(); if (resolution != 0.0) { KisSignalsBlocker b(m_page->printWidth, m_page->printHeight); m_page->printWidth->changeValue(m_page->pixelWidthDouble->value() / resolution); m_page->printHeight->changeValue(m_page->pixelHeightDouble->value() / resolution); } } void DlgImageSize::slotPrintResolutionChanged() { const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked(); if (printIsSeparate) { slotSyncPixelToPrintSize(); } else { slotSyncPrintToPixelSize(); } updatePrintSizeMaximum(); + updateAutoScaleFilter(); } void DlgImageSize::slotPrintResolutionUnitChanged() { qreal resolution = m_page->printResolution->value(); if (m_page->printResolutionUnit->currentText() == pixelsInchStr) { resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Centimeter)); } else { resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Inch)); } { KisSignalsBlocker b(m_page->printResolution); m_page->printResolution->setValue(resolution); } } void DlgImageSize::slotLockPixelRatioSwitched(bool value) { const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked(); if (!printIsSeparate) { m_page->printAspectRatioBtn->setKeepAspectRatio(value); } m_page->constrainProportionsCkb->setChecked(value); } void DlgImageSize::slotLockPrintRatioSwitched(bool value) { m_page->pixelAspectRatioBtn->setKeepAspectRatio(value); m_page->constrainProportionsCkb->setChecked(value); } void DlgImageSize::slotLockAllRatioSwitched(bool value) { const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked(); m_page->pixelAspectRatioBtn->setKeepAspectRatio(value); if (!printIsSeparate) { m_page->printAspectRatioBtn->setKeepAspectRatio(value); } } void DlgImageSize::slotAdjustSeparatelySwitched(bool value) { m_page->printAspectRatioBtn->setEnabled(!value); m_page->printAspectRatioBtn->setKeepAspectRatio(!value ? m_page->constrainProportionsCkb->isChecked() : true); } qreal DlgImageSize::currentResolutionPPI() const { qreal resolution = m_page->printResolution->value(); if (m_page->printResolutionUnit->currentText() == pixelsInchStr) { resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); } else { resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Point), KoUnit(KoUnit::Centimeter)); } return resolution; } void DlgImageSize::setCurrentResolutionPPI(qreal value) { qreal newValue = value; if (m_page->printResolutionUnit->currentText() == pixelsInchStr) { newValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Point)); } else { newValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Point)); } { KisSignalsBlocker b(m_page->printResolution); m_page->printResolution->setValue(newValue); } updatePrintSizeMaximum(); } void DlgImageSize::updatePrintSizeMaximum() { const qreal value = currentResolutionPPI(); if (value == 0.0) return; m_page->printWidth->setMaximum(maxImagePixelSize / value); m_page->printHeight->setMaximum(maxImagePixelSize / value); } + +void DlgImageSize::updateAutoScaleFilter() +{ + QSize newSize = QSize(width(), height()); + if (newSize == originalSize) { + autoScaleFilter = nullptr; + m_page->pixelFilterCmb->setItemText(0, ("Auto")); + return; + } + + autoScaleFilter = KisFilterStrategyRegistry::instance()->getAppropriateFilterStrategy(originalSize, newSize); + if (autoScaleFilter) { + m_page->pixelFilterCmb->setItemText(0, ("Auto (" + autoScaleFilter->name() + ")")); + } +} diff --git a/plugins/extensions/imagesize/dlg_imagesize.h b/plugins/extensions/imagesize/dlg_imagesize.h index 1d94a3fc92..6db662af52 100644 --- a/plugins/extensions/imagesize/dlg_imagesize.h +++ b/plugins/extensions/imagesize/dlg_imagesize.h @@ -1,96 +1,99 @@ /* * dlg_imagesize.h -- part of KimageShop^WKrayon^WKrita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2013 Juan Palacios * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DLG_IMAGESIZE #define DLG_IMAGESIZE #include class KisFilterStrategy; class WdgImageSize; class KisDocumentAwareSpinBoxUnitManager; class KisSpinBoxUnitManager; class KisAspectRatioLocker; #include "ui_wdg_imagesize.h" class WdgImageSize : public QWidget, public Ui::WdgImageSize { Q_OBJECT public: WdgImageSize(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class DlgImageSize: public KoDialog { Q_OBJECT public: static const QString PARAM_PREFIX; static const QString PARAM_IMSIZE_UNIT; static const QString PARAM_SIZE_UNIT; static const QString PARAM_RES_UNIT; static const QString PARAM_RATIO_LOCK; static const QString PARAM_PRINT_SIZE_SEPARATE; DlgImageSize(QWidget * parent, int width, int height, double resolution); ~DlgImageSize() override; qint32 width(); qint32 height(); double resolution(); - KisFilterStrategy *filterType(); + KisFilterStrategy *getFilterStrategy(); private Q_SLOTS: void slotSyncPrintToPixelSize(); void slotSyncPixelToPrintSize(); void slotPrintResolutionChanged(); void slotPrintResolutionUnitChanged(); void slotLockPixelRatioSwitched(bool value); void slotLockPrintRatioSwitched(bool value); void slotLockAllRatioSwitched(bool value); void slotAdjustSeparatelySwitched(bool value); + void updateAutoScaleFilter(); + private: qreal currentResolutionPPI() const; void setCurrentResolutionPPI(qreal value); void updatePrintSizeMaximum(); WdgImageSize *m_page; KisAspectRatioLocker *m_pixelSizeLocker; KisAspectRatioLocker *m_printSizeLocker; - KisDocumentAwareSpinBoxUnitManager* m_widthUnitManager; - KisDocumentAwareSpinBoxUnitManager* m_heightUnitManager; - KisSpinBoxUnitManager* m_printSizeUnitManager; + KisDocumentAwareSpinBoxUnitManager *m_widthUnitManager; + KisDocumentAwareSpinBoxUnitManager *m_heightUnitManager; + KisSpinBoxUnitManager *m_printSizeUnitManager; QSize originalSize; + KisFilterStrategy *autoScaleFilter; }; #endif // DLG_IMAGESIZE diff --git a/plugins/extensions/imagesize/imagesize.cc b/plugins/extensions/imagesize/imagesize.cc index 236afc02f1..6ffccfff98 100644 --- a/plugins/extensions/imagesize/imagesize.cc +++ b/plugins/extensions/imagesize/imagesize.cc @@ -1,198 +1,199 @@ /* * imagesize.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "imagesize.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_imagesize.h" #include "dlg_canvassize.h" #include "dlg_layersize.h" #include "kis_filter_strategy.h" #include "kis_action.h" #include "kis_action_manager.h" K_PLUGIN_FACTORY_WITH_JSON(ImageSizeFactory, "kritaimagesize.json", registerPlugin();) ImageSize::ImageSize(QObject *parent, const QVariantList &) : KisActionPlugin(parent) { KisAction *action = createAction("imagesize"); connect(action, SIGNAL(triggered()), this, SLOT(slotImageSize())); action = createAction("canvassize"); connect(action, SIGNAL(triggered()), this, SLOT(slotCanvasSize())); action = createAction("layersize"); connect(action, SIGNAL(triggered()), this, SLOT(slotLayerSize())); action = createAction("scaleAllLayers"); connect(action, SIGNAL(triggered()), this, SLOT(slotScaleAllLayers())); action = createAction("selectionscale"); connect(action, SIGNAL(triggered()), this, SLOT(slotSelectionScale())); } ImageSize::~ImageSize() { } void ImageSize::slotImageSize() { KisImageSP image = viewManager()->image().toStrongRef(); if (!image) return; if(!viewManager()->blockUntilOperationsFinished(image)) return; DlgImageSize * dlgImageSize = new DlgImageSize(viewManager()->mainWindow(), image->width(), image->height(), image->yRes()); Q_CHECK_PTR(dlgImageSize); dlgImageSize->setObjectName("ImageSize"); if (dlgImageSize->exec() == QDialog::Accepted) { qint32 w = dlgImageSize->width(); qint32 h = dlgImageSize->height(); double res = dlgImageSize->resolution(); - viewManager()->imageManager()->scaleCurrentImage(QSize(w, h), res, res, dlgImageSize->filterType()); + KisFilterStrategy *filter = dlgImageSize->getFilterStrategy(); + if (filter) viewManager()->imageManager()->scaleCurrentImage(QSize(w, h), res, res, filter); } delete dlgImageSize; } void ImageSize::slotCanvasSize() { KisImageWSP image = viewManager()->image(); if (!image) return; if(!viewManager()->blockUntilOperationsFinished(image)) return; DlgCanvasSize * dlgCanvasSize = new DlgCanvasSize(viewManager()->mainWindow(), image->width(), image->height(), image->yRes()); Q_CHECK_PTR(dlgCanvasSize); if (dlgCanvasSize->exec() == QDialog::Accepted) { qint32 width = dlgCanvasSize->width(); qint32 height = dlgCanvasSize->height(); qint32 xOffset = dlgCanvasSize->xOffset(); qint32 yOffset = dlgCanvasSize->yOffset(); viewManager()->imageManager()->resizeCurrentImage(width, height, xOffset, yOffset); } delete dlgCanvasSize; } void ImageSize::scaleLayerImpl(KisNodeSP rootNode) { KisImageWSP image = viewManager()->image(); if (!image) return; if(!viewManager()->blockUntilOperationsFinished(image)) return; QRect bounds; KisSelectionSP selection = viewManager()->selection(); if (selection) { bounds = selection->selectedExactRect(); } else { KisPaintDeviceSP dev = rootNode->projection(); KIS_SAFE_ASSERT_RECOVER_RETURN(dev); bounds = dev->exactBounds(); } DlgLayerSize * dlgLayerSize = new DlgLayerSize(viewManager()->mainWindow(), "LayerSize", bounds.width(), bounds.height(), image->yRes()); Q_CHECK_PTR(dlgLayerSize); dlgLayerSize->setCaption(i18n("Resize Layer")); if (dlgLayerSize->exec() == QDialog::Accepted) { qint32 w = dlgLayerSize->width(); qint32 h = dlgLayerSize->height(); viewManager()->image()->scaleNode(rootNode, QRectF(bounds).center(), qreal(w) / bounds.width(), qreal(h) / bounds.height(), dlgLayerSize->filterType(), selection); } delete dlgLayerSize; } void ImageSize::slotLayerSize() { scaleLayerImpl(viewManager()->activeNode()); } void ImageSize::slotScaleAllLayers() { KisImageWSP image = viewManager()->image(); if (!image) return; scaleLayerImpl(image->root()); } void ImageSize::slotSelectionScale() { KisImageSP image = viewManager()->image(); if (!image) return; if(!viewManager()->blockUntilOperationsFinished(image)) return; KisLayerSP layer = viewManager()->activeLayer(); KIS_ASSERT_RECOVER_RETURN(image && layer); KisSelectionMaskSP selectionMask = layer->selectionMask(); if (!selectionMask) { selectionMask = image->rootLayer()->selectionMask(); } KIS_ASSERT_RECOVER_RETURN(selectionMask); QRect rc = selectionMask->selection()->selectedExactRect(); DlgLayerSize * dlgSize = new DlgLayerSize(viewManager()->mainWindow(), "SelectionScale", rc.width(), rc.height(), image->yRes()); dlgSize->setCaption(i18n("Scale Selection")); if (dlgSize->exec() == QDialog::Accepted) { qint32 w = dlgSize->width(); qint32 h = dlgSize->height(); image->scaleNode(selectionMask, QRectF(rc).center(), qreal(w) / rc.width(), qreal(h) / rc.height(), dlgSize->filterType(), 0); } delete dlgSize; } #include "imagesize.moc"