diff --git a/libs/image/kis_filter_strategy.cc b/libs/image/kis_filter_strategy.cc index a9af92c969..7183382de9 100644 --- a/libs/image/kis_filter_strategy.cc +++ b/libs/image/kis_filter_strategy.cc @@ -1,262 +1,275 @@ /* * 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 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 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. + const int pixelArtThreshold = 128; + if (originalSize.width() <= pixelArtThreshold || + originalSize.height() <= pixelArtThreshold) { + return KisFilterStrategyRegistry::instance()->value("NearestNeighbor"); + } + + return KisFilterStrategyRegistry::instance()->value("Bicubic"); +} diff --git a/libs/image/kis_filter_strategy.h b/libs/image/kis_filter_strategy.h index c457f546c9..591f2905e3 100644 --- a/libs/image/kis_filter_strategy.h +++ b/libs/image/kis_filter_strategy.h @@ -1,227 +1,232 @@ /* * 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. */ #ifndef KIS_FILTER_STRATEGY_H_ #define KIS_FILTER_STRATEGY_H_ #include #include "KoGenericRegistry.h" #include "KoID.h" #include "kritaimage_export.h" class KRITAIMAGE_EXPORT KisFilterStrategy { public: KisFilterStrategy(KoID id) : m_id(id) {} virtual ~KisFilterStrategy() { } QString id() { return m_id.id(); } QString name() { return m_id.name(); } virtual qreal valueAt(qreal t, qreal weightsPositionScale) const { Q_UNUSED(t); Q_UNUSED(weightsPositionScale); return 0; } virtual qint32 intValueAt(qint32 t, qreal weightsPositionScale) const { return qint32(255*valueAt(t / 256.0, weightsPositionScale)); } virtual qreal support(qreal weightsPositionScale) { Q_UNUSED(weightsPositionScale); return supportVal; } virtual qint32 intSupport(qreal weightsPositionScale) { Q_UNUSED(weightsPositionScale); return intSupportVal; } virtual QString description() { return QString(); } protected: qreal supportVal; qint32 intSupportVal; KoID m_id; }; /* * KisAutoFilterStrategy is a 'metastrategy' which tries to automatically select * an appropriate scaling filter based on user parameters. */ class KRITAIMAGE_EXPORT KisAutoFilterStrategy : public KisFilterStrategy { public: KisAutoFilterStrategy() : KisFilterStrategy(KoID("Auto", i18n("Auto"))) {} ~KisAutoFilterStrategy() override {} QString description() override { return i18n("Attempt to automatically determine an appropriate scaling strategy."); } }; class KRITAIMAGE_EXPORT KisHermiteFilterStrategy : public KisFilterStrategy { public: KisHermiteFilterStrategy() : KisFilterStrategy(KoID("Hermite", i18n("Hermite"))) { supportVal = 1.0; intSupportVal = 256; } ~KisHermiteFilterStrategy() override {} qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisBicubicFilterStrategy : public KisFilterStrategy { public: KisBicubicFilterStrategy() : KisFilterStrategy(KoID("Bicubic", i18n("Bicubic"))) { supportVal = 2.0; intSupportVal = 512; } ~KisBicubicFilterStrategy() override {} QString description() override { return i18n("Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear."); } qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisBoxFilterStrategy : public KisFilterStrategy // Nearest Neighbor { public: KisBoxFilterStrategy() : KisFilterStrategy(KoID("NearestNeighbor", i18n("Nearest Neighbor"))) { // 0.5 and 128, but with a bit of margin to ensure the correct pixel will be used // even in case of calculation errors supportVal = 0.51; intSupportVal = 129; } ~KisBoxFilterStrategy() override {} QString description() override { return i18n("Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects."); } virtual qreal support(qreal weightsPositionScale) override; virtual qint32 intSupport(qreal weightsPositionScale) override; qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisBilinearFilterStrategy : public KisFilterStrategy { public: KisBilinearFilterStrategy() : KisFilterStrategy(KoID("Bilinear", i18n("Bilinear"))) { supportVal = 1.0; intSupportVal = 256; } ~KisBilinearFilterStrategy() override {} QString description() override { return i18n("Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size."); } qint32 intValueAt(qint32 t, qreal weightsPositionScale) const override; qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisBellFilterStrategy : public KisFilterStrategy { public: KisBellFilterStrategy() : KisFilterStrategy(KoID("Bell", i18n("Bell"))) { supportVal = 1.5; intSupportVal = 128 + 256; } ~KisBellFilterStrategy() override {} qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisBSplineFilterStrategy : public KisFilterStrategy { public: KisBSplineFilterStrategy() : KisFilterStrategy(KoID("BSpline", i18n("BSpline"))) { supportVal = 2.0; intSupportVal = 512; } ~KisBSplineFilterStrategy() override {} qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisLanczos3FilterStrategy : public KisFilterStrategy { public: KisLanczos3FilterStrategy() : KisFilterStrategy(KoID("Lanczos3", i18n("Lanczos3"))) { supportVal = 3.0; intSupportVal = 768; } ~KisLanczos3FilterStrategy() override {} QString description() override { return i18n("Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges."); } qreal valueAt(qreal t, qreal weightsPositionScale) const override; private: qreal sinc(qreal x) const; }; class KRITAIMAGE_EXPORT KisMitchellFilterStrategy : public KisFilterStrategy { public: KisMitchellFilterStrategy() : KisFilterStrategy(KoID("Mitchell", i18n("Mitchell"))) { supportVal = 2.0; intSupportVal = 256; } ~KisMitchellFilterStrategy() override {} qreal valueAt(qreal t, qreal weightsPositionScale) const override; }; class KRITAIMAGE_EXPORT KisFilterStrategyRegistry : public KoGenericRegistry { public: KisFilterStrategyRegistry(); ~KisFilterStrategyRegistry() override; static KisFilterStrategyRegistry* instance(); + /* + * Returns an appropriate filter strategy based on image scaling parameters. + */ + KisFilterStrategy *getAppropriateFilterStrategy(QSize originalSize, QSize desiredSize) const; + /** * This function return a list of all the keys in KoID format by using the name() method * on the objects stored in the registry. */ QList listKeys() const; /** * This function return a string formatted in HTML that contains the descriptions of all objects * (with a non empty description) stored in the registry. */ QString formattedDescriptions() const; private: KisFilterStrategyRegistry(const KisFilterStrategyRegistry&); KisFilterStrategyRegistry operator=(const KisFilterStrategyRegistry&); }; #endif // KIS_FILTER_STRATEGY_H_ diff --git a/plugins/extensions/imagesize/dlg_imagesize.cc b/plugins/extensions/imagesize/dlg_imagesize.cc index f587374e6e..ae3038ae5c 100644 --- a/plugins/extensions/imagesize/dlg_imagesize.cc +++ b/plugins/extensions/imagesize/dlg_imagesize.cc @@ -1,426 +1,433 @@ /* * 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) { setCaption(i18n("Scale To New Size")); setButtons(Ok | Cancel); setDefaultButton(Ok); 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("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); } 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() { KoID filterID = m_page->pixelFilterCmb->currentItem(); - KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value(filterID.id()); + + KisFilterStrategy *filter; + if (filterID.id() == "Auto") { + filter = KisFilterStrategyRegistry::instance()->getAppropriateFilterStrategy(QSize(), QSize(width(), height())); + } 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); } } 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(); } 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); }