diff --git a/libs/image/kis_filter_strategy.cc b/libs/image/kis_filter_strategy.cc index 06dc41e39b..5dc92e064a 100644 --- a/libs/image/kis_filter_strategy.cc +++ b/libs/image/kis_filter_strategy.cc @@ -1,238 +1,238 @@ /* * 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" Q_GLOBAL_STATIC(KisFilterStrategyRegistry, s_instance) qreal KisHermiteFilterStrategy::valueAt(qreal t) const { /* 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) const { /* 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 positve 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) const { /* 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 positve 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 positve 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) const { if ((t > -0.5) && (t <= 0.5)) return(1.0); return(0.0); } qint32 KisBoxFilterStrategy::intValueAt(qint32 t) const { /* f(t) = 1, -0.5 < t <= 0.5 */ if ((t > -128) && (t <= 128)) return 255; return 0; } qreal KisBilinearFilterStrategy::valueAt(qreal t) const { if (t < 0.0) t = -t; if (t < 1.0) return(1.0 - t); return(0.0); } qint32 KisBilinearFilterStrategy::intValueAt(qint32 t) const { /* 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) const { 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) const { 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) const { 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) const { 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 KisHermiteFilterStrategy); + s_instance->add(new KisHermiteFilterStrategy); s_instance->add(new KisBicubicFilterStrategy); s_instance->add(new KisBoxFilterStrategy); s_instance->add(new KisBilinearFilterStrategy); - // s_instance->add(new KisBellFilterStrategy); - // s_instance->add(new KisBSplineFilterStrategy); + s_instance->add(new KisBellFilterStrategy); + s_instance->add(new KisBSplineFilterStrategy); s_instance->add(new KisLanczos3FilterStrategy); - // s_instance->add(new KisMitchellFilterStrategy); + s_instance->add(new KisMitchellFilterStrategy); } 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::formatedDescriptions() const +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; } diff --git a/libs/image/kis_filter_strategy.h b/libs/image/kis_filter_strategy.h index 1cd5e36daf..68ea3029ad 100644 --- a/libs/image/kis_filter_strategy.h +++ b/libs/image/kis_filter_strategy.h @@ -1,206 +1,206 @@ /* * 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() {} + virtual ~KisFilterStrategy() { } QString id() { return m_id.id(); } QString name() { return m_id.name(); } virtual qreal valueAt(qreal /*t*/) const { return 0; } virtual qint32 intValueAt(qint32 t) const { return qint32(255*valueAt(t / 256.0)); } qreal support() { return supportVal; } qint32 intSupport() { return intSupportVal; } virtual bool boxSpecial() { return false; } virtual QString description() { return QString(); } protected: qreal supportVal; qint32 intSupportVal; KoID m_id; }; class KRITAIMAGE_EXPORT KisHermiteFilterStrategy : public KisFilterStrategy { public: KisHermiteFilterStrategy() : KisFilterStrategy(KoID("Hermite", i18n("Hermite"))) { supportVal = 1.0; intSupportVal = 256; } ~KisHermiteFilterStrategy() override {} qint32 intValueAt(qint32 t) const override; qreal valueAt(qreal t) 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) const override; }; class KRITAIMAGE_EXPORT KisBoxFilterStrategy : public KisFilterStrategy { public: KisBoxFilterStrategy() : KisFilterStrategy(KoID("Box", i18n("Box"))) { supportVal = 0.5; intSupportVal = 128; } ~KisBoxFilterStrategy() override {} QString description() override { return i18n("Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects."); } qint32 intValueAt(qint32 t) const override; qreal valueAt(qreal t) const override; bool boxSpecial() override { return true; } }; 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) const override; qreal valueAt(qreal t) 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) 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) 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) 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) const override; }; class KRITAIMAGE_EXPORT KisFilterStrategyRegistry : public KoGenericRegistry { public: KisFilterStrategyRegistry(); ~KisFilterStrategyRegistry() override; static KisFilterStrategyRegistry* instance(); /** * 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 formated in HTML that contains the descriptions of all objects * (with a non empty description) stored in the registry. */ - QString formatedDescriptions() const; + QString formattedDescriptions() const; private: KisFilterStrategyRegistry(const KisFilterStrategyRegistry&); KisFilterStrategyRegistry operator=(const KisFilterStrategyRegistry&); }; #endif // KIS_FILTER_STRATEGY_H_ diff --git a/libs/libkis/Document.cpp b/libs/libkis/Document.cpp index 9368f8c8e8..f7e5f97041 100644 --- a/libs/libkis/Document.cpp +++ b/libs/libkis/Document.cpp @@ -1,565 +1,549 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser 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 "Document.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct Document::Private { Private() {} QPointer document; }; Document::Document(KisDocument *document, QObject *parent) : QObject(parent) , d(new Private) { d->document = document; } Document::~Document() { delete d; } bool Document::operator==(const Document &other) const { return (d->document == other.d->document); } bool Document::operator!=(const Document &other) const { return !(operator==(other)); } bool Document::batchmode() const { if (!d->document) return false; return d->document->fileBatchMode(); } void Document::setBatchmode(bool value) { if (!d->document) return; d->document->setFileBatchMode(value); } Node *Document::activeNode() const { QList activeNodes; Q_FOREACH(QPointer view, KisPart::instance()->views()) { if (view && view->document() == d->document) { activeNodes << view->currentNode(); } } if (activeNodes.size() > 0) { return new Node(d->document->image(), activeNodes.first()); } return new Node(d->document->image(), d->document->image()->root()->firstChild()); } void Document::setActiveNode(Node* value) { if (!value->node()) return; KisMainWindow *mainWin = KisPart::instance()->currentMainwindow(); if (!mainWin) return; KisViewManager *viewManager = mainWin->viewManager(); if (!viewManager) return; if (viewManager->document() != d->document) return; KisNodeManager *nodeManager = viewManager->nodeManager(); if (!nodeManager) return; KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter(); if (!selectionAdapter) return; selectionAdapter->setActiveNode(value->node()); } QList Document::topLevelNodes() const { if (!d->document) return QList(); Node n(d->document->image(), d->document->image()->rootLayer()); return n.childNodes(); } Node *Document::nodeByName(const QString &name) const { if (!d->document) return 0; KisNodeSP node = d->document->image()->rootLayer()->findChildByName(name); return new Node(d->document->image(), node); } QString Document::colorDepth() const { if (!d->document) return ""; return d->document->image()->colorSpace()->colorDepthId().id(); } QString Document::colorModel() const { if (!d->document) return ""; return d->document->image()->colorSpace()->colorModelId().id(); } QString Document::colorProfile() const { if (!d->document) return ""; return d->document->image()->colorSpace()->profile()->name(); } bool Document::setColorProfile(const QString &value) { if (!d->document) return false; if (!d->document->image()) return false; const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(value); if (!profile) return false; bool retval = d->document->image()->assignImageProfile(profile); d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return retval; } bool Document::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile) { if (!d->document) return false; if (!d->document->image()) return false; const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile); if (!colorSpace) return false; d->document->image()->convertImageColorSpace(colorSpace, KoColorConversionTransformation::IntentPerceptual, KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization); d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return true; } QString Document::documentInfo() const { QDomDocument doc = KisDocument::createDomDocument("document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1"); doc = d->document->documentInfo()->save(doc); return doc.toString(); } void Document::setDocumentInfo(const QString &document) { KoXmlDocument doc; QString errorMsg; int errorLine, errorColumn; doc.setContent(document, &errorMsg, &errorLine, &errorColumn); d->document->documentInfo()->load(doc); } QString Document::fileName() const { if (!d->document) return QString::null; return d->document->url().toLocalFile(); } void Document::setFileName(QString value) { if (!d->document) return; d->document->setUrl(QUrl::fromLocalFile(value)); } int Document::height() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->height(); } void Document::setHeight(int value) { if (!d->document) return; if (!d->document->image()) return; resizeImage(d->document->image()->width(), value); } QString Document::name() const { if (!d->document) return ""; return d->document->documentInfo()->aboutInfo("title"); } void Document::setName(QString value) { if (!d->document) return; d->document->documentInfo()->setAboutInfo("title", value); } int Document::resolution() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return qRound(d->document->image()->xRes() * 72); } void Document::setResolution(int value) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; d->document->image()->setResolution(value / 72.0, value / 72.0); } Node *Document::rootNode() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return new Node(image, image->root()); } Selection *Document::selection() const { if (!d->document) return 0; if (!d->document->image()) return 0; if (!d->document->image()->globalSelection()) return 0; return new Selection(d->document->image()->globalSelection()); } void Document::setSelection(Selection* value) { if (!d->document) return; if (!d->document->image()) return; if (value) { d->document->image()->setGlobalSelection(value->selection()); } else { d->document->image()->setGlobalSelection(0); } } int Document::width() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->width(); } void Document::setWidth(int value) { if (!d->document) return; if (!d->document->image()) return; resizeImage(value, d->document->image()->height()); } double Document::xRes() const { if (!d->document) return 0.0; if (!d->document->image()) return 0.0; return d->document->image()->xRes(); } void Document::setXRes(double xRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(xRes, d->document->image()->yRes()); } double Document::yRes() const { if (!d->document) return 0.0; if (!d->document->image()) return 0.0; return d->document->image()->yRes(); } void Document::setYRes(double yRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(d->document->image()->xRes(), yRes); } QByteArray Document::pixelData(int x, int y, int w, int h) const { QByteArray ba; if (!d->document) return ba; KisImageSP image = d->document->image(); if (!image) return ba; KisPaintDeviceSP dev = image->projection(); ba.resize(w * h * dev->pixelSize()); dev->readBytes(reinterpret_cast(ba.data()), x, y, w, h); return ba; } bool Document::close() { bool retval = d->document->closeUrl(false); Q_FOREACH(KisView *view, KisPart::instance()->views()) { if (view->document() == d->document) { view->close(); view->deleteLater(); } } d->document->deleteLater(); d->document = 0; return retval; } void Document::crop(int x, int y, int w, int h) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc(x, y, w, h); image->cropImage(rc); } bool Document::exportImage(const QString &filename, const InfoObject &exportConfiguration) { if (!d->document) return false; QString mimeType = KisMimeDatabase::mimeTypeForFile(filename); d->document->setOutputMimeType(mimeType.toLatin1()); return d->document->exportDocument(QUrl::fromLocalFile(filename), exportConfiguration.configuration()); } void Document::flatten() { if (!d->document) return; if (!d->document->image()) return; d->document->image()->flatten(); } void Document::resizeImage(int w, int h) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setWidth(w); rc.setHeight(h); image->resizeImage(rc); } void Document::scaleImage(int w, int h, int xres, int yres, QString strategy) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setWidth(w); rc.setHeight(h); - KisFilterStrategy *actualStrategy = 0; - - if (strategy == "hermite") { - actualStrategy = new KisHermiteFilterStrategy(); - } else if (strategy == "bicubic") { - actualStrategy = new KisBicubicFilterStrategy(); - } else if (strategy == "box") { - actualStrategy = new KisBoxFilterStrategy(); - } else if (strategy == "bilinear") { - actualStrategy = new KisBilinearFilterStrategy(); - } else if (strategy == "bell") { - actualStrategy = new KisBellFilterStrategy(); - } else if (strategy == "bspline") { - actualStrategy = new KisBSplineFilterStrategy(); - } else if (strategy == "lanczos3") { - actualStrategy = new KisLanczos3FilterStrategy(); - } else if (strategy == "mitchell") { - actualStrategy = new KisMitchellFilterStrategy(); - } + KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy); + if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic"); + image->scaleImage(rc.size(), xres, yres, actualStrategy); } void Document::rotateImage(double radians) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; image->rotateImage(radians); } void Document::shearImage(double angleX, double angleY) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; image->shear(angleX, angleY); } bool Document::save() { if (!d->document) return false; return d->document->save(); } bool Document::saveAs(const QString &filename) { if (!d->document) return false; return d->document->saveAs(QUrl::fromLocalFile(filename)); } Node* Document::createNode(const QString &name, const QString &nodeType) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); Node *node = 0; if (nodeType == "paintlayer") { node = new Node(image, new KisPaintLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType == "grouplayer") { node = new Node(image, new KisGroupLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType == "filelayer") { node = new Node(image, new KisFileLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType == "filterlayer") { node = new Node(image, new KisAdjustmentLayer(image, name, 0, 0)); } else if (nodeType == "filllayer") { node = new Node(image, new KisGeneratorLayer(image, name, 0, 0)); } else if (nodeType == "clonelayer") { node = new Node(image, new KisCloneLayer(0, image, name, OPACITY_OPAQUE_U8)); } else if (nodeType == "vectorlayer") { node = new Node(image, new KisShapeLayer(d->document->shapeController(), image, name, OPACITY_OPAQUE_U8)); } else if (nodeType == "transparencymask") { node = new Node(image, new KisTransparencyMask()); } else if (nodeType == "filtermask") { node = new Node(image, new KisFilterMask()); } else if (nodeType == "transformmask") { node = new Node(image, new KisTransformMask()); } else if (nodeType == "selectionmask") { node = new Node(image, new KisSelectionMask(image)); } return node; } QImage Document::projection(int x, int y, int w, int h) const { if (!d->document || !d->document->image()) return QImage(); return d->document->image()->convertToQImage(x, y, w, h, 0); } QImage Document::thumbnail(int w, int h) const { if (!d->document || !d->document->image()) return QImage(); return d->document->generatePreview(QSize(w, h)).toImage(); } void Document::lock() { if (!d->document || !d->document->image()) return; d->document->image()->barrierLock(); } void Document::unlock() { if (!d->document || !d->document->image()) return; d->document->image()->unlock(); } void Document::waitForDone() { if (!d->document || !d->document->image()) return; d->document->image()->waitForDone(); } bool Document::tryBarrierLock() { if (!d->document || !d->document->image()) return false; return d->document->image()->tryBarrierLock(); } bool Document::isIdle() { if (!d->document || !d->document->image()) return false; return d->document->image()->isIdle(); } void Document::refreshProjection() { if (!d->document || !d->document->image()) return; d->document->image()->refreshGraph(); } QPointer Document::document() const { return d->document; } diff --git a/libs/libkis/Document.h b/libs/libkis/Document.h index e727e8dfb9..e17a52db01 100644 --- a/libs/libkis/Document.h +++ b/libs/libkis/Document.h @@ -1,513 +1,514 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser 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 LIBKIS_DOCUMENT_H #define LIBKIS_DOCUMENT_H #include #include "kritalibkis_export.h" #include "libkis.h" class KisDocument; /** * The Document class encapsulates a Krita Document/Image. A Krita document is an Image with * a filename. Libkis does not differentiate between a document and an image, like Krita does * internally. */ class KRITALIBKIS_EXPORT Document : public QObject { Q_OBJECT Q_DISABLE_COPY(Document) public: explicit Document(KisDocument *document, QObject *parent = 0); ~Document() override; bool operator==(const Document &other) const; bool operator!=(const Document &other) const; public Q_SLOTS: /** * Batchmode means that no actions on the document should show dialogs or popups. * @return true if the document is in batchmode. */ bool batchmode() const; /** * Set batchmode to @param value. If batchmode is true, then there should be no popups * or dialogs shown to the user. */ void setBatchmode(bool value); /** * @brief activeNode retrieve the node that is currently active in the currently active window * @return the active node. If there is no active window, the first child node is returned. */ Node* activeNode() const; /** * @brief setActiveNode make the given node active in the currently active view and window * @param value the node to make active. */ void setActiveNode(Node* value); /** * @brief toplevelNodes return a list with all top level nodes in the image graph */ QList topLevelNodes() const; /** * @brief nodeByName searches the node tree for a node with the given name and returns it * @param name the name of the node * @return the first node with the given name or 0 if no node is found */ Node *nodeByName(const QString &name) const; /** * colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return the color depth. */ QString colorDepth() const; /** * @brief colorModel retrieve the current color model of this document: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @return the internal color model string. */ QString colorModel() const; /** * @return the name of the current color profile */ QString colorProfile() const; /** * @brief setColorProfile set the color profile of the image to the given profile. The profile has to * be registered with krita and be compatible with the current color model and depth; the image data * is not converted. * @param colorProfile * @return false if the colorProfile name does not correspond to to a registered profile or if assigning * the profile failed. */ bool setColorProfile(const QString &colorProfile); /** * @brief setColorSpace convert the nodes and the image to the given colorspace. The conversion is * done with Perceptual as intent, High Quality and No LCMS Optimizations as flags and no blackpoint * compensation. * * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param colorProfile a valid color profile for this color model and color depth combination. * @return false the combination of these arguments does not correspond to a colorspace. */ bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); /** * @brief documentInfo creates and XML document representing document and author information. * @return a string containing a valid XML document with the right information about the document * and author. The DTD can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ * * @code * * * * * My Document * * * * * Unknown * 1 * 35 * 2017-02-27T20:15:09 * 2017-02-27T20:14:33 * * * * Boudewijn Rempt * * * * * * * * * * * * * * * @endcode * */ QString documentInfo() const; /** * @brief setDocumentInfo set the Document information to the information contained in document * @param document A string containing a valid XML document that conforms to the document-info DTD * that can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ */ void setDocumentInfo(const QString &document); /** * @return the full path to the document, if it has been set. */ QString fileName() const; /** * @brief setFileName set the full path of the document to @param value */ void setFileName(QString value); /** * @return the height of the image in pixels */ int height() const; /** * @brief setHeight resize the document to @param value height. This is a canvas resize, not a scale. */ void setHeight(int value); /** * @return the name of the document. This is the title field in the @see documentInfo */ QString name() const; /** * @brief setName sets the name of the document to @param value. This is the title field in the @see documentInfo */ void setName(QString value); /** * @return the resolution in pixels per inch */ int resolution() const; /** * @brief setResolution set the resolution of the image; this does not scale the image * @param value the resolution in pixels per inch */ void setResolution(int value); /** * @brief rootNode the root node is the invisible group layer that contains the entire node * hierarchy. * @return the root of the image */ Node* rootNode() const; /** * @brief selection Create a Selection object around the global selection, if there is one. * @return the global selection or None if there is no global selection. */ Selection* selection() const; /** * @brief setSelection set or replace the global selection * @param value a valid selection object. */ void setSelection(Selection* value); /** * @return the width of the image in pixels. */ int width() const; /** * @brief setWidth resize the document to @param value width. This is a canvas resize, not a scale. */ void setWidth(int value); /** * @return xRes the horizontal resolution of the image in pixels per pt (there are 72 pts to an inch) */ double xRes() const; /** * @brief setXRes set the horizontal resolution of the image to xRes in pixels per pt. (there are 72 pts to an inch) */ void setXRes(double xRes) const; /** * @return yRes the vertical resolution of the image in pixels per pt (there are 72 pts to an inch) */ double yRes() const; /** * @brief setYRes set the vertical resolution of the image to yRes in pixels per pt. (there are 72 pts to an inch) */ void setYRes(double yRes) const; /** * @brief pixelData reads the given rectangle from the image projection and returns it as a byte * array. The pixel data starts top-left, and is ordered row-first. * * The byte array can be interpreted as follows: 8 bits images have one byte per channel, * and as many bytes as there are channels. 16 bits integer images have two bytes per channel, * representing an unsigned short. 16 bits float images have two bytes per channel, representing * a half, or 16 bits float. 32 bits float images have four bytes per channel, representing a * float. * * You can read outside the image boundaries; those pixels will be transparent black. * * The order of channels is: * *
    *
  • Integer RGBA: Blue, Green, Red, Alpha *
  • Float RGBA: Red, Green, Blue, Alpha *
  • LabA: L, a, b, Alpha *
  • CMYKA: Cyan, Magenta, Yellow, Key, Alpha *
  • XYZA: X, Y, Z, A *
  • YCbCrA: Y, Cb, Cr, Alpha *
* * The byte array is a copy of the original image data. In Python, you can use bytes, bytearray * and the struct module to interpret the data and construct, for instance, a Pillow Image object. * * @param x x position from where to start reading * @param y y position from where to start reading * @param w row length to read * @param h number of rows to read * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray pixelData(int x, int y, int w, int h) const; /** * @brief close Close the document: remove it from Krita's internal list of documents and * close all views. If the document is modified, you should save it first. There will be * no prompt for saving. * @return true if the document is closed. */ bool close(); /** * @brief crop the image to rectangle described by @param x, @param y, * @param w and @param h */ void crop(int x, int y, int w, int h); /** * @brief exportImage export the image, without changing its URL to the given path. * @param filename the full path to which the image is to be saved * @param exportConfiguration a configuration object appropriate to the file format * @return true if the export succeeded, false if it failed. */ bool exportImage(const QString &filename, const InfoObject &exportConfiguration); /** * @brief flatten all layers in the image */ void flatten(); /** * @brief resizeImage resizes the canvas to the given width and height. * Note: This doesn't scale, use scale image for that. * @param w the new width * @param h the new height */ void resizeImage(int w, int h); /** * @brief scaleImage * @param w the new width * @param h the new height * @param xres the new xres * @param yres the new yres * @param strategy the scaling strategy. There's several ones amongst these that aren't available in the regular UI. + * The list of filters is extensible and can be retrieved with Krita::filter *
    - *
  • hermite
  • - *
  • bicubic - Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.
  • - *
  • box - Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.
  • - *
  • bilinear - 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.
  • - *
  • bell
  • - *
  • bspline
  • - *
  • lanczos3 - Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.
  • - *
  • mitchell
  • + *
  • Hermite
  • + *
  • Bicubic - Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.
  • + *
  • Box - Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.
  • + *
  • Bilinear - 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.
  • + *
  • Bell
  • + *
  • BSpline
  • + *
  • Kanczos3 - Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.
  • + *
  • Mitchell
  • *
*/ void scaleImage(int w, int h, int xres, int yres, QString strategy); /** * @brief rotateImage * Rotate the image by the given radians. * @param radians the amount you wish to rotate the image in radians */ void rotateImage(double radians); /** * @brief shearImage shear the whole image. * @param angleX the X-angle in degrees to shear by * @param angleY the Y-angle in degrees to shear by */ void shearImage(double angleX, double angleY); /** * @brief save the image to its currently set path. The modified flag of the * document will be reset * @return true if saving succeeded, false otherwise. */ bool save(); /** * @brief saveAs save the document under the @param filename. The document's * filename will be reset to @param filename. * @param filename the new filename (full path) for the document * @return true if saving succeeded, false otherwise. */ bool saveAs(const QString &filename); /** * @brief createNode create a new node of the given type. The node is not added * to the node hierarchy; you need to do that by finding the right parent node, * getting its list of child nodes and adding the node in the right place, then * calling Node::SetChildNodes * * @param name The name of the node * * @param nodeType The type of the node. Valid types are: *
    *
  • paintlayer *
  • grouplayer *
  • filelayer *
  • filterlayer *
  • filllayer *
  • clonelayer *
  • vectorlayer *
  • transparencymask *
  • filtermask *
  • transformmask *
  • selectionmask *
* * When relevant, the new Node will have the colorspace of the image by default; * that can be changed with Node::setColorSpace. * * The settings and selections for relevant layer and mask types can also be set * after the Node has been created. * * @return the new Node. */ Node* createNode(const QString &name, const QString &nodeType); /** * @brief projection creates a QImage from the rendered image or * a cutout rectangle. */ QImage projection(int x = 0, int y = 0, int w = 0, int h = 0) const; /** * @brief thumbnail create a thumbnail of the given dimensions. * * If the requested size is too big a null QImage is created. * * @return a QImage representing the layer contents. */ QImage thumbnail(int w, int h) const; /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void lock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void unlock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void waitForDone(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool tryBarrierLock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool isIdle(); /** * Starts a synchronous recomposition of the projection: everything will * wait until the image is fully recomputed. */ void refreshProjection(); private: friend class Krita; friend class Window; friend class Filter; QPointer document() const; private: struct Private; Private *const d; }; #endif // LIBKIS_DOCUMENT_H diff --git a/libs/libkis/Krita.cpp b/libs/libkis/Krita.cpp index 0275aeb97e..9012f5f1a7 100644 --- a/libs/libkis/Krita.cpp +++ b/libs/libkis/Krita.cpp @@ -1,377 +1,383 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser 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 "Krita.h" #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "View.h" #include "Document.h" #include "Window.h" #include "Extension.h" #include "DockWidgetFactoryBase.h" #include "Filter.h" #include "InfoObject.h" #include "Resource.h" Krita* Krita::s_instance = 0; struct Krita::Private { Private() {} QList extensions; bool batchMode {false}; Notifier *notifier{new Notifier()}; }; Krita::Krita(QObject *parent) : QObject(parent) , d(new Private) { qRegisterMetaType(); } Krita::~Krita() { qDeleteAll(d->extensions); delete d->notifier; delete d; } QList Krita::actions() const { QList actionList; KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return actionList; } KActionCollection *actionCollection = mainWindow->actionCollection(); Q_FOREACH(QAction *action, actionCollection->actions()) { actionList << new Action(action->objectName(), action); } return actionList; } Action *Krita::action(const QString &name) const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } KActionCollection *actionCollection = mainWindow->actionCollection(); QAction *action = actionCollection->action(name); if (action) { return new Action(name, action); } return 0; } Document* Krita::activeDocument() const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } KisView *view = mainWindow->activeView(); if (!view) { return 0; } KisDocument *document = view->document(); return new Document(document); } void Krita::setActiveDocument(Document* value) { Q_FOREACH(KisView *view, KisPart::instance()->views()) { if (view->document() == value->document().data()) { view->activateWindow(); break; } } } bool Krita::batchmode() const { return d->batchMode; } void Krita::setBatchmode(bool value) { d->batchMode = value; } QList Krita::documents() const { QList ret; foreach(QPointer doc, KisPart::instance()->documents()) { ret << new Document(doc); } return ret; } QStringList Krita::filters() const { QStringList ls = KisFilterRegistry::instance()->keys(); qSort(ls); return ls; } Filter *Krita::filter(const QString &name) const { if (!filters().contains(name)) return 0; Filter *filter = new Filter(); filter->setName(name); KisFilterSP f = KisFilterRegistry::instance()->value(name); KisFilterConfigurationSP fc = f->defaultConfiguration(); InfoObject *info = new InfoObject(fc); filter->setConfiguration(info); return filter; } +QStringList Krita::filterStrategies() const +{ + return KisFilterStrategyRegistry::instance()->keys(); +} + QStringList Krita::profiles(const QString &colorModel, const QString &colorDepth) const { QSet profileNames; QString id = KoColorSpaceRegistry::instance()->colorSpaceId(colorModel, colorDepth); QList profiles = KoColorSpaceRegistry::instance()->profilesFor(id); Q_FOREACH(const KoColorProfile *profile, profiles) { profileNames << profile->name(); } return profileNames.toList(); } bool Krita::addProfile(const QString &profilePath) { KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); return iccEngine->addProfile(profilePath); } Notifier* Krita::notifier() const { return d->notifier; } QString Krita::version() const { return KritaVersionWrapper::versionString(true); } QList Krita::views() const { QList ret; foreach(QPointer view, KisPart::instance()->views()) { ret << new View(view); } return ret; } Window *Krita::activeWindow() const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } return new Window(mainWindow); } QList Krita::windows() const { QList ret; foreach(QPointer mainWin, KisPart::instance()->mainWindows()) { ret << new Window(mainWin); } return ret; } QMap Krita::resources(const QString &type) const { QMap resources = QMap (); if (type == "pattern") { KoResourceServer* server = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (KoResource *res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type == "gradient") { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (KoResource *res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type == "brush") { KisBrushResourceServer* server = KisBrushServer::instance()->brushServer(); Q_FOREACH (KisBrushSP res, server->resources()) { resources[res->name()] = new Resource(res.data()); } } else if (type == "preset") { KisPaintOpPresetResourceServer* server = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (KisPaintOpPresetSP res, server->resources()) { resources[res->name()] = new Resource(res.data()); } } else if (type == "palette") { KoResourceServer* server = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (KoResource *res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type == "workspace") { KoResourceServer< KisWorkspaceResource >* server = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (KoResource *res, server->resources()) { resources[res->name()] = new Resource(res); } } return resources; } Document* Krita::createDocument(int width, int height, const QString &name, const QString &colorModel, const QString &colorDepth, const QString &profile) { KisDocument *document = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(document); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, profile); Q_ASSERT(cs); QColor qc(Qt::white); qc.setAlpha(0); KoColor bgColor(qc, cs); if (!document->newImage(name, width, height, cs, bgColor, true, 1, "", 100.0)) { qDebug() << "Could not create a new image"; return 0; } Q_ASSERT(document->image()); qDebug() << document->image()->objectName(); return new Document(document); } Document* Krita::openDocument(const QString &filename) { KisDocument *document = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(document); document->openUrl(QUrl::fromLocalFile(filename), KisDocument::OPEN_URL_FLAG_DO_NOT_ADD_TO_RECENT_FILES); return new Document(document); } Window* Krita::openWindow() { KisMainWindow *mw = KisPart::instance()->createMainWindow(); return new Window(mw); } Action *Krita::createAction(const QString &text) { KisAction *action = new KisAction(text, this); KisPart::instance()->addScriptAction(action); return new Action(action->objectName(), action); } void Krita::addExtension(Extension* extension) { d->extensions.append(extension); } QList< Extension* > Krita::extensions() { return d->extensions; } void Krita::writeSetting(const QString &group, const QString &name, const QString &value) { KConfigGroup grp = KSharedConfig::openConfig()->group(group); grp.writeEntry(name, value); } QString Krita::readSetting(const QString &group, const QString &name, const QString &defaultValue) { KConfigGroup grp = KSharedConfig::openConfig()->group(group); return grp.readEntry(name, defaultValue); } void Krita::addDockWidgetFactory(DockWidgetFactoryBase* factory) { KoDockRegistry::instance()->add(factory); } Krita* Krita::instance() { if (!s_instance) { s_instance = new Krita; } return s_instance; } /** * Scripter.fromVariant(variant) * variant is a QVariant * returns instance of QObject-subclass * * This is a helper method for PyQt because PyQt cannot cast a variant to a QObject or QWidget */ QObject *Krita::fromVariant(const QVariant& v) { if (v.canConvert< QWidget* >()) { QObject* obj = qvariant_cast< QWidget* >(v); return obj; } else if (v.canConvert< QObject* >()) { QObject* obj = qvariant_cast< QObject* >(v); return obj; } else return 0; } diff --git a/libs/libkis/Krita.h b/libs/libkis/Krita.h index 183e3d08ce..beefe0f47f 100644 --- a/libs/libkis/Krita.h +++ b/libs/libkis/Krita.h @@ -1,293 +1,301 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser 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 Lesser 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 LIBKIS_KRITA_H #define LIBKIS_KRITA_H #include #include "kritalibkis_export.h" #include "libkis.h" #include "Extension.h" #include "Document.h" #include "Window.h" #include "View.h" #include "Action.h" #include "Notifier.h" class QAction; /** * Krita is a singleton class that offers the root access to the Krita object hierarchy. * * The Krita.instance() is aliased as two builtins: Scripter and Application. */ class KRITALIBKIS_EXPORT Krita : public QObject { Q_OBJECT public: explicit Krita(QObject *parent = 0); ~Krita() override; public Q_SLOTS: /** * @return the currently active document, if there is one. */ Document* activeDocument() const; /** * @brief setActiveDocument activates the first view that shows the given document * @param value the document we want to activate */ void setActiveDocument(Document* value); /** * @brief batchmode determines whether the script is run in batch mode. If batchmode * is true, scripts should now show messageboxes or dialog boxes. * * Note that this separate from Document.setBatchmode(), which determines whether * export/save option dialogs are shown. * * @return true if the script is run in batchmode */ bool batchmode() const; /** * @brief setBatchmode sets the the batchmode to @param value; if true, scripts should * not show dialogs or messageboxes. */ void setBatchmode(bool value); /** * @return return a list of all actions for the currently active mainWindow. */ QList actions() const; /** * @return the action that has been registered under the given name, or 0 if no such action exists. */ Action *action(const QString &name) const; /** * @return a list of all open Documents */ QList documents() const; /** * @brief Filters are identified by an internal name. This function returns a list * of all existing registered filters. * @return a list of all registered filters */ QStringList filters() const; /** * @brief filter construct a Filter object with a default configuration. * @param name the name of the filter. Use Krita.instance().filters() to get * a list of all possible filters. * @return the filter or None if there is no such filter. */ Filter *filter(const QString &name) const; + /** + * @brief filterStrategies Retrieves all installed filter strategies. A filter + * strategy is used when transforming (scaling, shearing, rotating) an image to + * calculate the value of the new pixels. You can use th + * @return the id's of all available filters. + */ + QStringList filterStrategies() const; + /** * @brief profiles creates a list with the names of all color profiles compatible * with the given color model and color depth. * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return a list with valid names */ QStringList profiles(const QString &colorModel, const QString &colorDepth) const; /** * @brief addProfile load the given profile into the profile registry. * @param profilePath the path to the profile. * @return true if adding the profile succeeded. */ bool addProfile(const QString &profilePath); /** * @brief notifier the Notifier singleton emits signals when documents are opened and * closed, the configuration changes, views are opened and closed or windows are opened. * @return the notifier object */ Notifier* notifier() const; /** * @brief version Determine the version of Krita * * Usage: print(Application.version ()) * * @return the version string including git sha1 if Krita was built from git */ QString version() const; /** * @return a list of all views. A Document can be shown in more than one view. */ QList views() const; /** * @return the currently active window or None if there is no window */ Window *activeWindow() const; /** * @return a list of all windows */ QList windows() const; /** * @brief resources returns a list of Resource objects of the given type * @param type Valid types are: * *
    *
  • pattern
  • *
  • gradient
  • *
  • brush
  • *
  • preset
  • *
  • palette
  • *
  • workspace
  • *
*/ QMap resources(const QString &type) const; /** * @brief createDocument creates a new document and image and registers the document with the Krita application. * * The document will have one transparent layer. * * @param width the width in pixels * @param height the height in pixels * @param name the name of the image (not the filename of the document) * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param profile The name of an icc profile that is known to Krita. If an empty string is passed, the default is * taken. * @return the created document. */ Document *createDocument(int width, int height, const QString &name, const QString &colorModel, const QString &colorDepth, const QString &profile); /** * @brief openDocument creates a new Document, registers it with the Krita application and loads the given file. * @param filename the file to open in the document * @return the document */ Document *openDocument(const QString &filename); /** * @brief openWindow create a new main window. The window is not shown by default. */ Window *openWindow(); /** * @brief createAction creates an action with the given text and passes it to Krita. Every newly created * mainwindow will create an instance of this action. * @param text the user-visible text * @return the Action you can connect a slot to. */ Action *createAction(const QString &text); /** * @brief addExtension add the given plugin to Krita. There will be a single instance of each Extension in the Krita process. * @param extension the extension to add. */ void addExtension(Extension* extension); /** * return a list with all registered extension objects. */ QList extensions(); /** * @brief addDockWidgetFactory Add the given docker factory to the application. For scripts * loaded on startup, this means that every window will have one of the dockers created by the * factory. * @param factory The factory object. */ void addDockWidgetFactory(DockWidgetFactoryBase* factory ); /** * @brief writeSetting write the given setting under the given name to the kritarc file in * the given settings group. * @param group The group the setting belongs to. If empty, then the setting is written in the * general section * @param name The name of the setting * @param value The value of the setting. Script settings are always written as strings. */ void writeSetting(const QString &group, const QString &name, const QString &value); /** * @brief readSetting read the given setting value from the kritarc file. * @param group The group the setting is part of. If empty, then the setting is read from * the general group. * @param name The name of the setting * @param defaultValue The default value of the setting * @return a string representing the setting. */ QString readSetting(const QString &group, const QString &name, const QString &defaultValue); /** * @brief instance retrieve the singleton instance of the Application object. */ static Krita* instance(); // Internal only: for use with mikro.py static QObject *fromVariant(const QVariant& v); private: struct Private; Private *const d; static Krita* s_instance; }; Q_DECLARE_METATYPE(Notifier*); #endif // LIBKIS_KRITA_H diff --git a/plugins/extensions/imagesize/dlg_imagesize.cc b/plugins/extensions/imagesize/dlg_imagesize.cc index 846c7fa66b..65d48eaf16 100644 --- a/plugins/extensions/imagesize/dlg_imagesize.cc +++ b/plugins/extensions/imagesize/dlg_imagesize.cc @@ -1,422 +1,421 @@ /* * 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 "kis_double_parse_unit_spin_box.h" #include "kis_document_aware_spin_box_unit_manager.h" 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")); DlgImageSize::DlgImageSize(QWidget *parent, int width, int height, double resolution) : KoDialog(parent) , m_aspectRatio(((double) width) / height) , m_originalWidth(width) , m_originalHeight(height) , m_width(width) , m_height(height) , m_printWidth(width / resolution) , m_printHeight(height / resolution) , m_originalResolution(resolution) , m_resolution(resolution) , m_keepAspect(true) { 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"); _widthUnitManager = new KisDocumentAwareSpinBoxUnitManager(this); _heightUnitManager = new KisDocumentAwareSpinBoxUnitManager(this, KisDocumentAwareSpinBoxUnitManager::PIX_DIR_Y); //configure the unit to image length, default unit is pixel and printing units are forbiden. _widthUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH); _heightUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH); m_page->pixelWidthDouble->setUnitManager(_widthUnitManager); m_page->pixelHeightDouble->setUnitManager(_heightUnitManager); m_page->pixelWidthDouble->changeValue(width); m_page->pixelHeightDouble->changeValue(height); m_page->pixelWidthDouble->setDecimals(2); m_page->pixelHeightDouble->setDecimals(2); m_page->pixelWidthDouble->setDisplayUnit(false); m_page->pixelHeightDouble->setDisplayUnit(false); m_page->pixelWidthUnit->setModel(_widthUnitManager); m_page->pixelHeightUnit->setModel(_widthUnitManager); m_page->pixelWidthUnit->setCurrentText("px"); m_page->pixelHeightUnit->setCurrentText("px"); m_page->pixelFilterCmb->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); - m_page->pixelFilterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formatedDescriptions()); + m_page->pixelFilterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formattedDescriptions()); m_page->pixelFilterCmb->setCurrent("Bicubic"); _printWidthUnitManager = new KisSpinBoxUnitManager(this); _printHeightUnitManager = new KisSpinBoxUnitManager(this); m_page->printWidth->setUnitManager(_printWidthUnitManager); m_page->printHeight->setUnitManager(_printHeightUnitManager); 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(_printWidthUnitManager); m_page->printHeightUnit->setModel(_printHeightUnitManager); m_page->printWidth->changeValue(m_printWidth); m_page->printHeight->changeValue(m_printHeight); //TODO: create a resolution dimension in the unit manager. m_page->printResolutionUnit->addItem(pixelsInchStr); m_page->printResolutionUnit->addItem(pixelsCentimeterStr); m_page->pixelAspectRatioBtn->setKeepAspectRatio(true); m_page->printAspectRatioBtn->setKeepAspectRatio(true); m_page->constrainProportionsCkb->setChecked(true); 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->pixelWidthUnit); comboboxesGroup->addWidget(m_page->pixelHeightUnit); comboboxesGroup->addWidget(m_page->printWidthUnit); comboboxesGroup->addWidget(m_page->printHeightUnit); comboboxesGroup->addWidget(m_page->printResolutionUnit); connect(this, SIGNAL(okClicked()), this, SLOT(accept())); connect(m_page->pixelAspectRatioBtn, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(slotAspectChanged(bool))); connect(m_page->printAspectRatioBtn, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(slotAspectChanged(bool))); connect(m_page->constrainProportionsCkb, SIGNAL(toggled(bool)), this, SLOT(slotAspectChanged(bool))); connect(m_page->pixelWidthDouble, SIGNAL(valueChangedPt(double)), this, SLOT(slotPixelWidthChanged(double))); connect(m_page->pixelHeightDouble, SIGNAL(valueChangedPt(double)), this, SLOT(slotPixelHeightChanged(double))); connect(m_page->pixelWidthUnit, SIGNAL(currentIndexChanged(int)), _widthUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(m_page->pixelHeightUnit, SIGNAL(currentIndexChanged(int)), _heightUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(_widthUnitManager, SIGNAL(unitChanged(int)), m_page->pixelWidthUnit, SLOT(setCurrentIndex(int))); connect(_heightUnitManager, SIGNAL(unitChanged(int)), m_page->pixelHeightUnit, SLOT(setCurrentIndex(int))); connect(m_page->printWidth, SIGNAL(valueChangedPt(double)), this, SLOT(slotPrintWidthChanged(double))); connect(m_page->printHeight, SIGNAL(valueChangedPt(double)), this, SLOT(slotPrintHeightChanged(double))); connect(m_page->printWidthUnit, SIGNAL(currentIndexChanged(int)), _printWidthUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(m_page->printHeightUnit, SIGNAL(currentIndexChanged(int)), _printHeightUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(_printWidthUnitManager, SIGNAL(unitChanged(int)), m_page->printWidthUnit, SLOT(setCurrentIndex(int))); connect(_printHeightUnitManager, SIGNAL(unitChanged(int)), m_page->printHeightUnit, SLOT(setCurrentIndex(int))); connect(m_page->printResolution, SIGNAL(valueChanged(double)), this, SLOT(slotPrintResolutionChanged(double))); connect(m_page->printResolution, SIGNAL(editingFinished()), this, SLOT(slotPrintResolutionEditFinished())); connect(m_page->printResolutionUnit, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPrintResolutionUnitChanged())); // pick selected print units from user locale (after slots connection, so the spinbox will be updated too). if (QLocale().measurementSystem() == QLocale::MetricSystem) { m_page->printWidthUnit->setCurrentText("cm"); m_page->printHeightUnit->setCurrentText("cm"); m_page->printResolutionUnit->setCurrentIndex(0); // Pixels/Centimeter slotPrintResolutionUnitChanged(); //ensure the resolution is updated, even if the index didn't changed. } else { // Imperial m_page->printWidthUnit->setCurrentText("in"); m_page->printHeightUnit->setCurrentText("in"); m_page->printResolutionUnit->setCurrentIndex(1); // Pixels/Inch slotPrintResolutionUnitChanged(); //ensure the resolution is updated, even if the index didn't changed. } setMainWidget(m_page); } DlgImageSize::~DlgImageSize() { delete m_page; } qint32 DlgImageSize::width() { return (qint32)m_width; } qint32 DlgImageSize::height() { return (qint32)m_height; } double DlgImageSize::resolution() { return m_resolution; } KisFilterStrategy *DlgImageSize::filterType() { KoID filterID = m_page->pixelFilterCmb->currentItem(); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value(filterID.id()); return filter; } // SLOTS void DlgImageSize::slotPixelWidthChanged(double w) { m_width = w; m_printWidth = m_width / m_resolution; updatePrintWidthUIValue(m_printWidth); if (m_keepAspect) { m_height = qRound(m_width / m_aspectRatio); updatePixelHeightUIValue(m_height); m_printHeight = m_height / m_resolution; updatePrintHeightUIValue(m_printHeight); } } void DlgImageSize::slotPixelHeightChanged(double h) { m_height = h; m_printHeight = m_height / m_resolution; updatePrintHeightUIValue(m_printHeight); if (m_keepAspect) { m_width = qRound(m_height * m_aspectRatio); updatePixelWidthUIValue(m_width); m_printWidth = m_width / m_resolution; updatePrintWidthUIValue(m_printWidth); } } void DlgImageSize::slotPrintWidthChanged(double w) { m_printWidth = w; if (m_keepAspect) { m_printHeight = m_printWidth / m_aspectRatio; updatePrintHeightUIValue(m_printHeight); } if (m_page->adjustPrintSizeSeparatelyCkb->isChecked()) { m_resolution = m_width / m_printWidth; updatePrintResolutionUIValue(m_resolution); if (!m_keepAspect) { // compute and update a new image height value from the print size values const double printHeightInch = KoUnit::convertFromUnitToUnit(m_printHeight, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); m_height = qRound(printHeightInch * 72 * m_resolution); updatePixelHeightUIValue(m_height); } } else { const double printWidthInch = KoUnit::convertFromUnitToUnit(m_printWidth, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); m_width = qRound(printWidthInch * 72 * m_resolution); updatePixelWidthUIValue(m_width); if (m_keepAspect) { m_height = qRound(m_width / m_aspectRatio); updatePixelHeightUIValue(m_height); } } } void DlgImageSize::slotPrintHeightChanged(double h) { m_printHeight = h; if (m_keepAspect) { m_printWidth = m_printHeight * m_aspectRatio; updatePrintWidthUIValue(m_printWidth); } if (m_page->adjustPrintSizeSeparatelyCkb->isChecked()) { m_resolution = m_height / m_printHeight; updatePrintResolutionUIValue(m_resolution); if (!m_keepAspect) { // compute and update a new image width value from the print size values const double printWidthInch = KoUnit::convertFromUnitToUnit(m_printWidth, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); m_width = qRound(printWidthInch * 72 * m_resolution); updatePixelWidthUIValue(m_width); } } else { const double printHeightInch = KoUnit::convertFromUnitToUnit(m_printHeight, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); m_height = qRound(printHeightInch * 72 * m_resolution); updatePixelHeightUIValue(m_height); if (m_keepAspect) { m_width = qRound(m_height * m_aspectRatio); updatePixelWidthUIValue(m_width); } } } void DlgImageSize::slotAspectChanged(bool keep) { m_page->pixelAspectRatioBtn->blockSignals(true); m_page->printAspectRatioBtn->blockSignals(true); m_page->constrainProportionsCkb->blockSignals(true); m_page->pixelAspectRatioBtn->setKeepAspectRatio(keep); m_page->printAspectRatioBtn->setKeepAspectRatio(keep); m_page->constrainProportionsCkb->setChecked(keep); m_page->pixelAspectRatioBtn->blockSignals(false); m_page->printAspectRatioBtn->blockSignals(false); m_page->constrainProportionsCkb->blockSignals(false); m_keepAspect = keep; if (keep) { // values may be out of sync, so we need to reset it to defaults m_width = m_originalWidth; m_height = m_originalHeight; m_printWidth = m_originalWidth / m_originalResolution; m_printHeight = m_originalHeight / m_originalResolution; m_resolution = m_originalResolution; updatePixelWidthUIValue(m_width); updatePixelHeightUIValue(m_height); updatePrintWidthUIValue(m_printWidth); updatePrintHeightUIValue(m_printHeight); updatePrintResolutionUIValue(m_resolution); } } void DlgImageSize::slotPrintResolutionChanged(double r) { if (m_page->printResolutionUnit->currentText() == pixelsInchStr) m_resolution = KoUnit::convertFromUnitToUnit(r, KoUnit(KoUnit::Pixel), KoUnit(KoUnit::Inch)); else m_resolution = KoUnit::convertFromUnitToUnit(r, KoUnit(KoUnit::Pixel), KoUnit(KoUnit::Centimeter)); if (m_page->adjustPrintSizeSeparatelyCkb->isChecked()) { m_printWidth = m_width / m_resolution; m_printHeight = m_height / m_resolution; updatePrintWidthUIValue(m_printWidth); updatePrintHeightUIValue(m_printHeight); } else { // Do not commit m_width and m_height values yet. This is done to avoid // nasty results in image size values while the user is typing a resolution value const double printWidthInch = KoUnit::convertFromUnitToUnit(m_printWidth, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); const int width = qRound(printWidthInch * 72 * m_resolution); const double printHeightInch = KoUnit::convertFromUnitToUnit(m_printHeight, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); const int height = qRound(printHeightInch * 72 * m_resolution); updatePixelWidthUIValue(width); updatePixelHeightUIValue(height); } } void DlgImageSize::slotPrintResolutionEditFinished() { if (!m_page->adjustPrintSizeSeparatelyCkb->isChecked()) { const double printWidthInch = KoUnit::convertFromUnitToUnit(m_printWidth, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); const double printHeightInch = KoUnit::convertFromUnitToUnit(m_printHeight, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch)); // Commit width and height values m_width = qRound(printWidthInch * 72 * m_resolution); m_height = qRound(printHeightInch * 72 * m_resolution); // Note that spinbox values should be up to date // (updated through slotResolutionChanged()) } } void DlgImageSize::slotPrintResolutionUnitChanged() { updatePrintResolutionUIValue(m_resolution); } void DlgImageSize::updatePixelWidthUIValue(double value) { m_page->pixelWidthDouble->blockSignals(true); m_page->pixelWidthDouble->changeValue(value); m_page->pixelWidthDouble->blockSignals(false); } void DlgImageSize::updatePixelHeightUIValue(double value) { m_page->pixelHeightDouble->blockSignals(true); m_page->pixelHeightDouble->changeValue(value); m_page->pixelHeightDouble->blockSignals(false); } void DlgImageSize::updatePrintWidthUIValue(double value) { m_page->printWidth->blockSignals(true); m_page->printWidth->changeValue(value); m_page->printWidth->blockSignals(false); } void DlgImageSize::updatePrintHeightUIValue(double value) { m_page->printHeight->blockSignals(true); m_page->printHeight->changeValue(value); m_page->printHeight->blockSignals(false); } void DlgImageSize::updatePrintResolutionUIValue(double value) { double uiValue = 0.0; if (m_page->printResolutionUnit->currentText() == pixelsInchStr) { // show the value in pixel/inch unit uiValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Pixel)); } else { // show the value in pixel/centimeter unit uiValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Pixel)); } m_page->printResolution->blockSignals(true); m_page->printResolution->setValue(uiValue); m_page->printResolution->blockSignals(false); } diff --git a/plugins/extensions/imagesize/dlg_layersize.cc b/plugins/extensions/imagesize/dlg_layersize.cc index 621eaf24e3..290b9f829f 100644 --- a/plugins/extensions/imagesize/dlg_layersize.cc +++ b/plugins/extensions/imagesize/dlg_layersize.cc @@ -1,197 +1,197 @@ /* * dlg_layersize.cc - part of Krita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Sven Langkamp * 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_layersize.h" #include #include #include #include // XXX: I'm really real bad at arithmetic, let alone math. Here // be rounding errors. (Boudewijn) static const QString pixelStr(KoUnit::unitDescription(KoUnit::Pixel)); static const QString percentStr(i18n("Percent (%)")); DlgLayerSize::DlgLayerSize(QWidget * parent, const char * name, int width, int height, double resolution) : KoDialog(parent) , m_aspectRatio(((double) width) / height) , m_originalWidth(width) , m_originalHeight(height) , m_width(width) , m_height(height) , m_resolution(resolution) , m_keepAspect(true) { setCaption(i18n("Layer Size")); setObjectName(name); setButtons(Ok | Cancel); setDefaultButton(Ok); m_page = new WdgLayerSize(this); Q_CHECK_PTR(m_page); m_page->layout()->setMargin(0); m_page->setObjectName(name); _widthUnitManager = new KisDocumentAwareSpinBoxUnitManager(this); _heightUnitManager = new KisDocumentAwareSpinBoxUnitManager(this, KisDocumentAwareSpinBoxUnitManager::PIX_DIR_Y); _widthUnitManager->setApparentUnitFromSymbol("px"); _heightUnitManager->setApparentUnitFromSymbol("px"); m_page->newWidthDouble->setUnitManager(_widthUnitManager); m_page->newHeightDouble->setUnitManager(_heightUnitManager); m_page->newWidthDouble->setDecimals(2); m_page->newHeightDouble->setDecimals(2); m_page->newWidthDouble->setDisplayUnit(false); m_page->newHeightDouble->setDisplayUnit(false); m_page->newWidthDouble->setValue(width); m_page->newWidthDouble->setFocus(); m_page->newHeightDouble->setValue(height); m_page->filterCmb->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); - m_page->filterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formatedDescriptions()); + m_page->filterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formattedDescriptions()); m_page->filterCmb->setCurrent("Bicubic"); m_page->newWidthUnit->setModel(_widthUnitManager); m_page->newHeightUnit->setModel(_heightUnitManager); const int pixelUnitIndex = _widthUnitManager->getsUnitSymbolList().indexOf("px"); //TODO: have a better way to identify units. m_page->newWidthUnit->setCurrentIndex(pixelUnitIndex); m_page->newHeightUnit->setCurrentIndex(pixelUnitIndex); m_page->aspectRatioBtn->setKeepAspectRatio(true); m_page->constrainProportionsCkb->setChecked(true); setMainWidget(m_page); connect(this, SIGNAL(okClicked()), this, SLOT(accept())); connect(m_page->aspectRatioBtn, SIGNAL(keepAspectRatioChanged(bool)), this, SLOT(slotAspectChanged(bool))); connect(m_page->constrainProportionsCkb, SIGNAL(toggled(bool)), this, SLOT(slotAspectChanged(bool))); connect(m_page->newWidthDouble, SIGNAL(valueChangedPt(double)), this, SLOT(slotWidthChanged(double))); connect(m_page->newHeightDouble, SIGNAL(valueChangedPt(double)), this, SLOT(slotHeightChanged(double))); connect(m_page->newWidthUnit, SIGNAL(currentIndexChanged(int)), _widthUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(m_page->newHeightUnit, SIGNAL(currentIndexChanged(int)), _heightUnitManager, SLOT(selectApparentUnitFromIndex(int))); connect(_widthUnitManager, SIGNAL(unitChanged(int)), m_page->newWidthUnit, SLOT(setCurrentIndex(int))); connect(_heightUnitManager, SIGNAL(unitChanged(int)), m_page->newHeightUnit, SLOT(setCurrentIndex(int))); } DlgLayerSize::~DlgLayerSize() { delete m_page; } qint32 DlgLayerSize::width() { return (qint32)m_width; } qint32 DlgLayerSize::height() { return (qint32)m_height; } KisFilterStrategy *DlgLayerSize::filterType() { KoID filterID = m_page->filterCmb->currentItem(); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value(filterID.id()); return filter; } // SLOTS void DlgLayerSize::slotWidthChanged(double w) { //this slot receiv values in pt from the unitspinbox, so just use the resolution. const double resValue = w*_widthUnitManager->getConversionFactor(KisSpinBoxUnitManager::LENGTH, "px"); m_width = qRound(resValue); if (m_keepAspect) { m_height = qRound(m_width / m_aspectRatio); m_page->newHeightDouble->blockSignals(true); m_page->newHeightDouble->changeValue(w / m_aspectRatio); m_page->newHeightDouble->blockSignals(false); } } void DlgLayerSize::slotHeightChanged(double h) { //this slot receiv values in pt from the unitspinbox, so just use the resolution. const double resValue = h*_heightUnitManager->getConversionFactor(KisSpinBoxUnitManager::LENGTH, "px"); m_height = qRound(resValue); if (m_keepAspect) { m_width = qRound(m_height * m_aspectRatio); m_page->newWidthDouble->blockSignals(true); m_page->newWidthDouble->changeValue(h * m_aspectRatio); m_page->newWidthDouble->blockSignals(false); } } void DlgLayerSize::slotAspectChanged(bool keep) { m_page->aspectRatioBtn->blockSignals(true); m_page->constrainProportionsCkb->blockSignals(true); m_page->aspectRatioBtn->setKeepAspectRatio(keep); m_page->constrainProportionsCkb->setChecked(keep); m_page->aspectRatioBtn->blockSignals(false); m_page->constrainProportionsCkb->blockSignals(false); m_keepAspect = keep; if (keep) { // values may be out of sync, so we need to reset it to defaults m_width = m_originalWidth; m_height = m_originalHeight; updateWidthUIValue(m_width); updateHeightUIValue(m_height); } } void DlgLayerSize::updateWidthUIValue(double value) { m_page->newWidthDouble->blockSignals(true); const double resValue = value/_widthUnitManager->getConversionFactor(KisSpinBoxUnitManager::LENGTH, "px"); m_page->newWidthDouble->changeValue(resValue); m_page->newWidthDouble->blockSignals(false); } void DlgLayerSize::updateHeightUIValue(double value) { m_page->newHeightDouble->blockSignals(true); const double resValue = value/_heightUnitManager->getConversionFactor(KisSpinBoxUnitManager::LENGTH, "px"); m_page->newHeightDouble->changeValue(resValue); m_page->newHeightDouble->blockSignals(false); } diff --git a/plugins/extensions/pykrita/sip/krita/Krita.sip b/plugins/extensions/pykrita/sip/krita/Krita.sip index 07677e84ec..98d2cb8d49 100644 --- a/plugins/extensions/pykrita/sip/krita/Krita.sip +++ b/plugins/extensions/pykrita/sip/krita/Krita.sip @@ -1,57 +1,58 @@ class Krita : QObject { %TypeHeaderCode #include "Krita.h" %End public: public Q_SLOTS: Krita(QObject* parent /TransferThis/ = 0); virtual ~Krita(); Document * activeDocument() const /Factory/; void setActiveDocument(Document* value); bool batchmode() const; void setBatchmode(bool value); QList actions() const /Factory/; Action * action(const QString & name) const; QList documents() const /Factory/; QStringList filters() const; Filter * filter(const QString &name) const /Factory/; + QStringList filterStrategies() const; QStringList profiles(const QString &colorModel, const QString &ColorDepth) const; bool addProfile(const QString &profilePath); Notifier * notifier() const; QString version() const; QList views() const /Factory/; Window * activeWindow() const /Factory/; QList windows() const /Factory/; QMap resources(const QString &type) const /Factory/; Document * createDocument(int width, int height, const QString &name, const QString &colorModel, const QString &colorDepth, const QString &profile) /Factory/; Document * openDocument(const QString &filename) /Factory/; Window * openWindow(); Action * createAction(const QString & text); void addExtension(Extension* _extension /GetWrapper/); %MethodCode Py_BEGIN_ALLOW_THREADS sipCpp->addExtension(a0); Py_END_ALLOW_THREADS sipTransferTo(a0Wrapper, Py_None); %End void addDockWidgetFactory(DockWidgetFactoryBase* _factory /GetWrapper/); %MethodCode Py_BEGIN_ALLOW_THREADS sipCpp->addDockWidgetFactory(a0); Py_END_ALLOW_THREADS sipTransferTo(a0Wrapper, Py_None); %End void writeSetting(const QString &group, const QString &name, const QString &value); QString readSetting(const QString &group, const QString &name, const QString &defaultValue); static Krita * instance(); static QObject * fromVariant(const QVariant & v); private: Krita(const Krita &); // Generated };