diff --git a/libs/brush/CMakeLists.txt b/libs/brush/CMakeLists.txt index 704906c8b9..0965983d00 100644 --- a/libs/brush/CMakeLists.txt +++ b/libs/brush/CMakeLists.txt @@ -1,51 +1,51 @@ add_subdirectory( tests ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ) set(kritalibbrush_LIB_SRCS kis_predefined_brush_factory.cpp kis_auto_brush.cpp kis_boundary.cc kis_brush.cpp kis_scaling_size_brush.cpp kis_brush_registry.cpp kis_brush_server.cpp - kis_gbr_brush.cpp + kis_gimp_brush.cpp kis_abr_brush.cpp kis_abr_brush_collection.cpp kis_imagepipe_brush.cpp kis_pipebrush_parasite.cpp kis_png_brush.cpp kis_svg_brush.cpp kis_qimage_pyramid.cpp kis_text_brush.cpp kis_auto_brush_factory.cpp kis_text_brush_factory.cpp ) add_library(kritalibbrush SHARED ${kritalibbrush_LIB_SRCS} ) generate_export_header(kritalibbrush BASE_NAME kritabrush EXPORT_MACRO_NAME BRUSH_EXPORT) if (WIN32) target_link_libraries(kritalibbrush kritaimage Qt5::Svg ${WIN32_PLATFORM_NET_LIBS}) else () target_link_libraries(kritalibbrush kritaimage Qt5::Svg) endif () if(HAVE_VC) include_directories(SYSTEM ${Vc_INCLUDE_DIR}) target_link_libraries(kritalibbrush ${Vc_LIBRARIES}) # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Vc_DEFINITIONS}") endif() target_link_libraries(kritalibbrush LINK_INTERFACE_LIBRARIES kritaimage Qt5::Svg) set_target_properties(kritalibbrush PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritalibbrush ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/brush/kis_brush_server.cpp b/libs/brush/kis_brush_server.cpp index 75dfedf474..bb268228c8 100644 --- a/libs/brush/kis_brush_server.cpp +++ b/libs/brush/kis_brush_server.cpp @@ -1,161 +1,161 @@ /* * Copyright (c) 2008 Boudewijn Rempt * * 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_brush_server.h" #include #include #include #include #include #include #include #include "kis_abr_brush.h" #include "kis_abr_brush_collection.h" -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_imagepipe_brush.h" #include "kis_png_brush.h" #include "kis_svg_brush.h" Q_GLOBAL_STATIC(KisBrushServer, s_instance) class BrushResourceServer : public KisBrushResourceServer { public: BrushResourceServer() : KisBrushResourceServer("kis_brushes", "*.gbr:*.gih:*.abr:*.png:*.svg") { } ///Reimplemented virtual bool importResourceFile(const QString& filename, bool fileCreation = true) { QFileInfo fi(filename); if (fi.exists() == false) return false; if (fi.size() == 0) return false; if (fi.suffix().toLower() == "abr") { if (fileCreation) { QFile::copy(filename, saveLocation() + fi.fileName()); } QList collectionResources = createResources(filename); Q_FOREACH (KisBrushSP brush, collectionResources) { addResource(brush); } } else { return KisBrushResourceServer::importResourceFile(filename, fileCreation); } qApp->processEvents(QEventLoop::AllEvents); return true; } private: ///Reimplemented virtual QList createResources(const QString & filename) { QList brushes; QString fileExtension = QFileInfo(filename).suffix().toLower(); if (fileExtension == "abr") { KisAbrBrushCollection collection(filename); collection.load(); Q_FOREACH (KisAbrBrush * abrBrush, collection.brushes()) { // abrBrush->setBrushTipImage(QImage()); brushes.append(abrBrush); addTag(abrBrush, collection.filename()); } } else { brushes.append(createResource(filename)); } return brushes; } ///Reimplemented virtual KisBrushSP createResource(const QString & filename) { QString fileExtension = QFileInfo(filename).suffix().toLower(); KisBrushSP brush; if (fileExtension == "gbr") { - brush = new KisGbrBrush(filename); + brush = new KisGimpBrush(filename); } else if (fileExtension == "gih") { brush = new KisImagePipeBrush(filename); } else if (fileExtension == "png") { brush = new KisPngBrush(filename); } else if (fileExtension == "svg") { brush = new KisSvgBrush(filename); } return brush; } }; KisBrushServer::KisBrushServer() { m_brushServer = new BrushResourceServer(); if (!QFileInfo(m_brushServer->saveLocation()).exists()) { QDir().mkpath(m_brushServer->saveLocation()); } m_brushThread = new KoResourceLoaderThread(m_brushServer); m_brushThread->loadSynchronously(); // m_brushThread->barrier(); Q_FOREACH (KisBrushSP brush, m_brushServer->resources()) { if (!dynamic_cast(brush.data())) { brush->setBrushTipImage(QImage()); } } } KisBrushServer::~KisBrushServer() { dbgRegistry << "deleting KisBrushServer"; delete m_brushThread; delete m_brushServer; } KisBrushServer* KisBrushServer::instance() { return s_instance; } KisBrushResourceServer* KisBrushServer::brushServer(bool block) { if (block) m_brushThread->barrier(); return m_brushServer; } void KisBrushServer::slotRemoveBlacklistedResources() { m_brushServer->removeBlackListedFiles(); } diff --git a/libs/brush/kis_gbr_brush.cpp b/libs/brush/kis_gimp_brush.cpp similarity index 91% rename from libs/brush/kis_gbr_brush.cpp rename to libs/brush/kis_gimp_brush.cpp index d25aa1d341..5b40a2b582 100644 --- a/libs/brush/kis_gbr_brush.cpp +++ b/libs/brush/kis_gimp_brush.cpp @@ -1,508 +1,508 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Adrian Page * Copyright (c) 2005 Bart Coppens * Copyright (c) 2007 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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 #include -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include #include #include #include #include #include #include #include #include "kis_datamanager.h" #include "kis_paint_device.h" #include "kis_global.h" #include "kis_image.h" struct GimpBrushV1Header { quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 width; /* width of brush */ quint32 height; /* height of brush */ quint32 bytes; /* depth of brush in bytes */ }; /// All fields are in MSB on disk! struct GimpBrushHeader { quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 width; /* width of brush */ quint32 height; /* height of brush */ quint32 bytes; /* depth of brush in bytes */ /* The following are only defined in version 2 */ quint32 magic_number; /* GIMP brush magic number */ quint32 spacing; /* brush spacing as % of width & height, 0 - 1000 */ }; // Needed, or the GIMP won't open it! quint32 const GimpV2BrushMagic = ('G' << 24) + ('I' << 16) + ('M' << 8) + ('P' << 0); -struct KisGbrBrush::Private { +struct KisGimpBrush::Private { QByteArray data; bool ownData; /* seems to indicate that @ref data is owned by the brush, but in Qt4.x this is already guaranteed... so in reality it seems more to indicate whether the data is loaded from file (ownData = true) or memory (ownData = false) */ bool useColorAsMask; quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 bytes; /* depth of brush in bytes */ quint32 magic_number; /* GIMP brush magic number */ }; #define DEFAULT_SPACING 0.25 -KisGbrBrush::KisGbrBrush(const QString& filename) +KisGimpBrush::KisGimpBrush(const QString& filename) : KisScalingSizeBrush(filename) , d(new Private) { d->ownData = true; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); } -KisGbrBrush::KisGbrBrush(const QString& filename, +KisGimpBrush::KisGimpBrush(const QString& filename, const QByteArray& data, qint32 & dataPos) : KisScalingSizeBrush(filename) , d(new Private) { d->ownData = false; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); d->data = QByteArray::fromRawData(data.data() + dataPos, data.size() - dataPos); init(); d->data.clear(); dataPos += d->header_size + (width() * height() * d->bytes); } -KisGbrBrush::KisGbrBrush(KisPaintDeviceSP image, int x, int y, int w, int h) +KisGimpBrush::KisGimpBrush(KisPaintDeviceSP image, int x, int y, int w, int h) : KisScalingSizeBrush() , d(new Private) { d->ownData = true; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); initFromPaintDev(image, x, y, w, h); } -KisGbrBrush::KisGbrBrush(const QImage& image, const QString& name) +KisGimpBrush::KisGimpBrush(const QImage& image, const QString& name) : KisScalingSizeBrush() , d(new Private) { d->ownData = false; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); setBrushTipImage(image); setName(name); } -KisGbrBrush::KisGbrBrush(const KisGbrBrush& rhs) +KisGimpBrush::KisGimpBrush(const KisGimpBrush& rhs) : KisScalingSizeBrush(rhs) , d(new Private(*rhs.d)) { setName(rhs.name()); d->data = QByteArray(); setValid(rhs.valid()); } -KisGbrBrush::~KisGbrBrush() +KisGimpBrush::~KisGimpBrush() { delete d; } -bool KisGbrBrush::load() +bool KisGimpBrush::load() { QFile file(filename()); if (file.size() == 0) return false; file.open(QIODevice::ReadOnly); bool res = loadFromDevice(&file); file.close(); return res; } -bool KisGbrBrush::loadFromDevice(QIODevice *dev) +bool KisGimpBrush::loadFromDevice(QIODevice *dev) { if (d->ownData) { d->data = dev->readAll(); } return init(); } -bool KisGbrBrush::init() +bool KisGimpBrush::init() { GimpBrushHeader bh; if (sizeof(GimpBrushHeader) > (uint)d->data.size()) { return false; } memcpy(&bh, d->data, sizeof(GimpBrushHeader)); bh.header_size = qFromBigEndian(bh.header_size); d->header_size = bh.header_size; bh.version = qFromBigEndian(bh.version); d->version = bh.version; bh.width = qFromBigEndian(bh.width); bh.height = qFromBigEndian(bh.height); bh.bytes = qFromBigEndian(bh.bytes); d->bytes = bh.bytes; bh.magic_number = qFromBigEndian(bh.magic_number); d->magic_number = bh.magic_number; if (bh.version == 1) { // No spacing in version 1 files so use Gimp default bh.spacing = static_cast(DEFAULT_SPACING * 100); } else { bh.spacing = qFromBigEndian(bh.spacing); if (bh.spacing > 1000) { return false; } } setSpacing(bh.spacing / 100.0); if (bh.header_size > (uint)d->data.size() || bh.header_size == 0) { return false; } QString name; if (bh.version == 1) { // Version 1 has no magic number or spacing, so the name // is at a different offset. Character encoding is undefined. const char *text = d->data.constData() + sizeof(GimpBrushV1Header); name = QString::fromLatin1(text, bh.header_size - sizeof(GimpBrushV1Header) - 1); } else { // ### Version = 3->cinepaint; may be float16 data! // Version >=2: UTF-8 encoding is used name = QString::fromUtf8(d->data.constData() + sizeof(GimpBrushHeader), bh.header_size - sizeof(GimpBrushHeader) - 1); } setName(name); if (bh.width == 0 || bh.height == 0) { return false; } QImage::Format imageFormat; if (bh.bytes == 1) { imageFormat = QImage::Format_Indexed8; } else { imageFormat = QImage::Format_ARGB32; } QImage image(QImage(bh.width, bh.height, imageFormat)); if (image.isNull()) { return false; } qint32 k = bh.header_size; if (bh.bytes == 1) { QVector table; for (int i = 0; i < 256; ++i) table.append(qRgb(i, i, i)); image.setColorTable(table); // Grayscale if (static_cast(k + bh.width * bh.height) > d->data.size()) { return false; } setHasColor(false); for (quint32 y = 0; y < bh.height; y++) { uchar *pixel = reinterpret_cast(image.scanLine(y)); for (quint32 x = 0; x < bh.width; x++, k++) { qint32 val = 255 - static_cast(d->data[k]); *pixel = val; ++pixel; } } } else if (bh.bytes == 4) { // RGBA if (static_cast(k + (bh.width * bh.height * 4)) > d->data.size()) { return false; } setHasColor(true); for (quint32 y = 0; y < bh.height; y++) { QRgb *pixel = reinterpret_cast(image.scanLine(y)); for (quint32 x = 0; x < bh.width; x++, k += 4) { *pixel = qRgba(d->data[k], d->data[k + 1], d->data[k + 2], d->data[k + 3]); ++pixel; } } } else { warnKrita << "WARNING: loading of GBR brushes with" << bh.bytes << "bytes per pixel is not supported"; return false; } setWidth(image.width()); setHeight(image.height()); if (d->ownData) { d->data.resize(0); // Save some memory, we're using enough of it as it is. } setValid(image.width() != 0 && image.height() != 0); setBrushTipImage(image); return true; } -bool KisGbrBrush::initFromPaintDev(KisPaintDeviceSP image, int x, int y, int w, int h) +bool KisGimpBrush::initFromPaintDev(KisPaintDeviceSP image, int x, int y, int w, int h) { // Forcefully convert to RGBA8 // XXX profile and exposure? setBrushTipImage(image->convertToQImage(0, x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags())); setName(image->objectName()); setHasColor(true); return true; } -bool KisGbrBrush::save() +bool KisGimpBrush::save() { QFile file(filename()); file.open(QIODevice::WriteOnly | QIODevice::Truncate); bool ok = saveToDevice(&file); file.close(); return ok; } -bool KisGbrBrush::saveToDevice(QIODevice* dev) const +bool KisGimpBrush::saveToDevice(QIODevice* dev) const { GimpBrushHeader bh; QByteArray utf8Name = name().toUtf8(); // Names in v2 brushes are in UTF-8 char const* name = utf8Name.data(); int nameLength = qstrlen(name); int wrote; bh.header_size = qToBigEndian((quint32)sizeof(GimpBrushHeader) + nameLength + 1); bh.version = qToBigEndian((quint32)2); // Only RGBA8 data needed atm, no cinepaint stuff bh.width = qToBigEndian((quint32)width()); bh.height = qToBigEndian((quint32)height()); // Hardcoded, 4 bytes RGBA or 1 byte GREY if (!hasColor()) { bh.bytes = qToBigEndian((quint32)1); } else { bh.bytes = qToBigEndian((quint32)4); } bh.magic_number = qToBigEndian((quint32)GimpV2BrushMagic); bh.spacing = qToBigEndian(static_cast(spacing() * 100.0)); // Write header: first bh, then the name QByteArray bytes = QByteArray::fromRawData(reinterpret_cast(&bh), sizeof(GimpBrushHeader)); wrote = dev->write(bytes); bytes.clear(); if (wrote == -1) { return false; } wrote = dev->write(name, nameLength + 1); if (wrote == -1) { return false; } int k = 0; QImage image = brushTipImage(); if (!hasColor()) { bytes.resize(width() * height()); for (qint32 y = 0; y < height(); y++) { for (qint32 x = 0; x < width(); x++) { QRgb c = image.pixel(x, y); bytes[k++] = static_cast(255 - qRed(c)); // red == blue == green } } } else { bytes.resize(width() * height() * 4); for (qint32 y = 0; y < height(); y++) { for (qint32 x = 0; x < width(); x++) { // order for gimp brushes, v2 is: RGBA QRgb pixel = image.pixel(x, y); bytes[k++] = static_cast(qRed(pixel)); bytes[k++] = static_cast(qGreen(pixel)); bytes[k++] = static_cast(qBlue(pixel)); bytes[k++] = static_cast(qAlpha(pixel)); } } } wrote = dev->write(bytes); if (wrote == -1) { return false; } KoResource::saveToDevice(dev); return true; } -QImage KisGbrBrush::brushTipImage() const +QImage KisGimpBrush::brushTipImage() const { QImage image = KisBrush::brushTipImage(); if (hasColor() && useColorAsMask()) { for (int y = 0; y < image.height(); y++) { QRgb *pixel = reinterpret_cast(image.scanLine(y)); for (int x = 0; x < image.width(); x++) { QRgb c = pixel[x]; int a = qGray(c); pixel[x] = qRgba(a, a, a, qAlpha(c)); } } } return image; } -enumBrushType KisGbrBrush::brushType() const +enumBrushType KisGimpBrush::brushType() const { return !hasColor() || useColorAsMask() ? MASK : IMAGE; } -void KisGbrBrush::setBrushType(enumBrushType type) +void KisGimpBrush::setBrushType(enumBrushType type) { Q_UNUSED(type); - qFatal("FATAL: protected member setBrushType has no meaning for KisGbrBrush"); + qFatal("FATAL: protected member setBrushType has no meaning for KisGimpBrush"); } -void KisGbrBrush::setBrushTipImage(const QImage& image) +void KisGimpBrush::setBrushTipImage(const QImage& image) { KisBrush::setBrushTipImage(image); setValid(true); } -void KisGbrBrush::makeMaskImage() +void KisGimpBrush::makeMaskImage() { if (!hasColor()) { return; } QImage brushTip = brushTipImage(); if (brushTip.width() == width() && brushTip.height() == height()) { int imageWidth = width(); int imageHeight = height(); QImage image(imageWidth, imageHeight, QImage::Format_Indexed8); QVector table; for (int i = 0; i < 256; ++i) { table.append(qRgb(i, i, i)); } image.setColorTable(table); for (int y = 0; y < imageHeight; y++) { QRgb *pixel = reinterpret_cast(brushTip.scanLine(y)); uchar * dstPixel = image.scanLine(y); for (int x = 0; x < imageWidth; x++) { QRgb c = pixel[x]; float alpha = qAlpha(c) / 255.0f; // linear interpolation with maximum gray value which is transparent in the mask //int a = (qGray(c) * alpha) + ((1.0 - alpha) * 255); // single multiplication version int a = 255 + alpha * (qGray(c) - 255); dstPixel[x] = (uchar)a; } } setBrushTipImage(image); } setHasColor(false); setUseColorAsMask(false); resetBoundary(); clearBrushPyramid(); } -KisBrush* KisGbrBrush::clone() const +KisBrush* KisGimpBrush::clone() const { - return new KisGbrBrush(*this); + return new KisGimpBrush(*this); } -void KisGbrBrush::toXML(QDomDocument& d, QDomElement& e) const +void KisGimpBrush::toXML(QDomDocument& d, QDomElement& e) const { predefinedBrushToXML("gbr_brush", e); e.setAttribute("ColorAsMask", QString::number((int)useColorAsMask())); KisBrush::toXML(d, e); } -void KisGbrBrush::setUseColorAsMask(bool useColorAsMask) +void KisGimpBrush::setUseColorAsMask(bool useColorAsMask) { /** * WARNING: There is a problem in the brush server, since it * returns not copies of brushes, but direct pointers to them. It * means that the brushes are shared among all the currently * present paintops, which might be a problem for e.g. Multihand * Brush Tool. * * Right now, all the instances of Multihand Brush Tool share the * same brush, so there is no problem in this sharing, unless we * reset the internal state of the brush on our way. */ if (useColorAsMask != d->useColorAsMask) { d->useColorAsMask = useColorAsMask; resetBoundary(); clearBrushPyramid(); } } -bool KisGbrBrush::useColorAsMask() const +bool KisGimpBrush::useColorAsMask() const { return d->useColorAsMask; } -QString KisGbrBrush::defaultFileExtension() const +QString KisGimpBrush::defaultFileExtension() const { return QString(".gbr"); } diff --git a/libs/brush/kis_gbr_brush.h b/libs/brush/kis_gimp_brush.h similarity index 89% rename from libs/brush/kis_gbr_brush.h rename to libs/brush/kis_gimp_brush.h index faefbe335a..0c1af26e93 100644 --- a/libs/brush/kis_gbr_brush.h +++ b/libs/brush/kis_gimp_brush.h @@ -1,122 +1,122 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * * 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_GBR_BRUSH_ #define KIS_GBR_BRUSH_ #include #include #include "kis_scaling_size_brush.h" #include #include #include #include "kritabrush_export.h" class KisQImagemask; typedef KisSharedPtr KisQImagemaskSP; class QString; class QIODevice; -class BRUSH_EXPORT KisGbrBrush : public KisScalingSizeBrush +class BRUSH_EXPORT KisGimpBrush : public KisScalingSizeBrush { protected: public: /// Construct brush to load filename later as brush - KisGbrBrush(const QString& filename); + KisGimpBrush(const QString& filename); /// Load brush from the specified data, at position dataPos, and set the filename - KisGbrBrush(const QString& filename, + KisGimpBrush(const QString& filename, const QByteArray & data, qint32 & dataPos); /// Load brush from the specified paint device, in the specified region - KisGbrBrush(KisPaintDeviceSP image, int x, int y, int w, int h); + KisGimpBrush(KisPaintDeviceSP image, int x, int y, int w, int h); /// Load brush as a copy from the specified QImage (handy when you need to copy a brush!) - KisGbrBrush(const QImage& image, const QString& name = QString("")); + KisGimpBrush(const QImage& image, const QString& name = QString("")); - virtual ~KisGbrBrush(); + virtual ~KisGimpBrush(); virtual bool load(); virtual bool loadFromDevice(QIODevice *dev); virtual bool save(); virtual bool saveToDevice(QIODevice* dev) const; /** * @return a preview of the brush */ virtual QImage brushTipImage() const; /** * If the brush image data are colorful (e.g. you created the brush from the canvas with custom brush) * and you want to paint with it as with masks, set to true. */ virtual void setUseColorAsMask(bool useColorAsMask); virtual bool useColorAsMask() const; /** * Convert the mask to inverted gray scale, so it is alpha mask. * It can be used as MASK brush type. This operates on the date of the brush, * so it destruct the original brush data */ virtual void makeMaskImage(); virtual enumBrushType brushType() const; /** * Makes a copy of this brush. */ virtual KisBrush* clone() const; /** * @return default file extension for saving the brush */ virtual QString defaultFileExtension() const; protected: /** * save the content of this brush to an IO device */ friend class KisImageBrushesPipe; - KisGbrBrush(const KisGbrBrush& rhs); + KisGimpBrush(const KisGimpBrush& rhs); void setBrushType(enumBrushType type); virtual void setBrushTipImage(const QImage& image); void toXML(QDomDocument& d, QDomElement& e) const; private: bool init(); bool initFromPaintDev(KisPaintDeviceSP image, int x, int y, int w, int h); struct Private; Private* const d; }; #endif // KIS_GBR_BRUSH_ diff --git a/libs/brush/kis_imagepipe_brush.cpp b/libs/brush/kis_imagepipe_brush.cpp index e8ff371d34..c0951b2597 100644 --- a/libs/brush/kis_imagepipe_brush.cpp +++ b/libs/brush/kis_imagepipe_brush.cpp @@ -1,502 +1,502 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Bart Coppens * * 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_imagepipe_brush.h" #include "kis_pipebrush_parasite.h" #include "kis_brushes_pipe.h" -class KisImageBrushesPipe : public KisBrushesPipe +class KisImageBrushesPipe : public KisBrushesPipe { public: KisImageBrushesPipe() : m_isInitialized(false) { } /* pre and post are split because: 21:12:20 < dmitryK> boud: i guess it was somehow related to the fact that the maskWidth/maskHeight should correspond to the size of the mask returned by paintDevice() 21:13:33 < dmitryK> boud: the random stuff is called once per brush->paintDevice() call, after the device is returned to the paint op, that is "preparing the randomness for the next call" 21:14:16 < dmitryK> boud: and brushesPipe->currentBrush() always returning the same brush for any particular paintInfo. */ protected: static int selectPre(KisParasite::SelectionMode mode, int index, int rank, const KisPaintInformation& info) { qreal angle; switch (mode) { case KisParasite::Constant: case KisParasite::Incremental: case KisParasite::Random: break; case KisParasite::Pressure: index = static_cast(info.pressure() * (rank - 1) + 0.5); break; case KisParasite::Angular: // + m_d->PI_2 to be compatible with the gimp angle = info.drawingAngle() + M_PI_2; angle = normalizeAngle(angle); index = static_cast(angle / (2.0 * M_PI) * rank); break; case KisParasite::TiltX: index = qRound(info.xTilt() / 2.0 * rank) + rank / 2; break; case KisParasite::TiltY: index = qRound(info.yTilt() / 2.0 * rank) + rank / 2; break; default: warnImage << "Parasite" << mode << "is not implemented"; index = 0; } return index; } static int selectPost(KisParasite::SelectionMode mode, int index, int rank, const KisPaintInformation& info) { switch (mode) { case KisParasite::Constant: break; case KisParasite::Incremental: index = (index + 1) % rank; break; case KisParasite::Random: index = info.randomSource()->generate(0, rank); break; case KisParasite::Pressure: case KisParasite::Angular: break; case KisParasite::TiltX: case KisParasite::TiltY: break; default: warnImage << "Parasite" << mode << "is not implemented"; index = 0; } return index; } int chooseNextBrush(const KisPaintInformation& info) { quint32 brushIndex = 0; if (!m_isInitialized) { /** * Reset all the indexes to the initial values and do the * generation based on parameters. */ for (int i = 0; i < m_parasite.dim; i++) { m_parasite.index[i] = 0; } updateBrushIndexes(info); m_isInitialized = true; } for (int i = 0; i < m_parasite.dim; i++) { int index = selectPre(m_parasite.selection[i], m_parasite.index[i], m_parasite.rank[i], info); brushIndex += m_parasite.brushesCount[i] * index; } brushIndex %= m_brushes.size(); return brushIndex; } void updateBrushIndexes(const KisPaintInformation& info) { for (int i = 0; i < m_parasite.dim; i++) { m_parasite.index[i] = selectPost(m_parasite.selection[i], m_parasite.index[i], m_parasite.rank[i], info); } } public: - using KisBrushesPipe::addBrush; + using KisBrushesPipe::addBrush; void setParasite(const KisPipeBrushParasite& parasite) { m_parasite = parasite; } const KisPipeBrushParasite& parasite() const { return m_parasite; } void setUseColorAsMask(bool useColorAsMask) { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGimpBrush * brush, m_brushes) { brush->setUseColorAsMask(useColorAsMask); } } void makeMaskImage() { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGimpBrush * brush, m_brushes) { brush->makeMaskImage(); } } bool saveToDevice(QIODevice* dev) const { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGimpBrush * brush, m_brushes) { if (!brush->saveToDevice(dev)) { return false; } } return true; } void notifyStrokeStarted() { m_isInitialized = false; } private: KisPipeBrushParasite m_parasite; bool m_isInitialized; }; struct KisImagePipeBrush::Private { public: KisImageBrushesPipe brushesPipe; }; KisImagePipeBrush::KisImagePipeBrush(const QString& filename) - : KisGbrBrush(filename) + : KisGimpBrush(filename) , m_d(new Private()) { } KisImagePipeBrush::KisImagePipeBrush(const QString& name, int w, int h, QVector< QVector > devices, QVector modes) - : KisGbrBrush("") + : KisGimpBrush("") , m_d(new Private()) { Q_ASSERT(devices.count() == modes.count()); Q_ASSERT(devices.count() > 0); Q_ASSERT(devices.count() < 2); // XXX Multidimensionals not supported yet, change to MaxDim! setName(name); KisPipeBrushParasite parasite; parasite.dim = devices.count(); // XXX Change for multidim! : parasite.ncells = devices.at(0).count(); parasite.rank[0] = parasite.ncells; // ### This can masquerade some bugs, be careful here in the future parasite.selection[0] = modes.at(0); // XXX needsmovement! parasite.setBrushesCount(); setParasite(parasite); setDevices(devices, w, h); setBrushTipImage(m_d->brushesPipe.firstBrush()->brushTipImage()); } KisImagePipeBrush::KisImagePipeBrush(const KisImagePipeBrush& rhs) - : KisGbrBrush(rhs), + : KisGimpBrush(rhs), m_d(new Private(*rhs.m_d)) { } KisImagePipeBrush::~KisImagePipeBrush() { delete m_d; } bool KisImagePipeBrush::load() { QFile file(filename()); file.open(QIODevice::ReadOnly); bool res = loadFromDevice(&file); file.close(); return res; } bool KisImagePipeBrush::loadFromDevice(QIODevice *dev) { QByteArray data = dev->readAll(); return initFromData(data); } bool KisImagePipeBrush::initFromData(const QByteArray &data) { if (data.size() == 0) return false; // XXX: this doesn't correctly load the image pipe brushes yet. // XXX: This stuff is in utf-8, too. // The first line contains the name -- this means we look until we arrive at the first newline QByteArray line1; qint32 i = 0; while (data[i] != '\n' && i < data.size()) { line1.append(data[i]); i++; } setName(QString::fromUtf8(line1, line1.size())); i++; // Skip past the first newline // The second line contains the number of brushes, separated by a space from the parasite // XXX: This stuff is in utf-8, too. QByteArray line2; while (data[i] != '\n' && i < data.size()) { line2.append(data[i]); i++; } QString paramline = QString::fromUtf8(line2, line2.size()); qint32 numOfBrushes = paramline.left(paramline.indexOf(' ')).toUInt(); QString parasiteString = paramline.mid(paramline.indexOf(' ') + 1); KisPipeBrushParasite parasite = KisPipeBrushParasite(parasiteString); parasite.sanitize(); m_d->brushesPipe.setParasite(parasite); i++; // Skip past the second newline for (int brushIndex = 0; brushIndex < numOfBrushes && i < data.size(); brushIndex++) { - KisGbrBrush* brush = new KisGbrBrush(name() + '_' + QString().setNum(brushIndex), + KisGimpBrush* brush = new KisGimpBrush(name() + '_' + QString().setNum(brushIndex), data, i); m_d->brushesPipe.addBrush(brush); } if (numOfBrushes > 0) { setValid(true); setSpacing(m_d->brushesPipe.lastBrush()->spacing()); setWidth(m_d->brushesPipe.firstBrush()->width()); setHeight(m_d->brushesPipe.firstBrush()->height()); setBrushTipImage(m_d->brushesPipe.firstBrush()->brushTipImage()); } return true; } bool KisImagePipeBrush::save() { QFile file(filename()); file.open(QIODevice::WriteOnly | QIODevice::Truncate); bool ok = saveToDevice(&file); file.close(); return ok; } bool KisImagePipeBrush::saveToDevice(QIODevice* dev) const { QByteArray utf8Name = name().toUtf8(); // Names in v2 brushes are in UTF-8 char const* name = utf8Name.data(); int len = qstrlen(name); if (m_d->brushesPipe.parasite().dim != 1) { warnImage << "Save to file for pipe brushes with dim != not yet supported!"; return false; } // Save this pipe brush: first the header, and then all individual brushes consecutively // XXX: this needs some care for when we have > 1 dimension) // Gimp Pipe Brush header format: Name\n \n // The name\n if (dev->write(name, len) == -1) return false; if (!dev->putChar('\n')) return false; // Write the parasite (also writes number of brushes) if (!m_d->brushesPipe.parasite().saveToDevice(dev)) return false; if (!dev->putChar('\n')) return false; KoResource::saveToDevice(dev); // return m_d->brushesPipe.saveToDevice(dev); } void KisImagePipeBrush::notifyStrokeStarted() { m_d->brushesPipe.notifyStrokeStarted(); } void KisImagePipeBrush::notifyCachedDabPainted(const KisPaintInformation& info) { m_d->brushesPipe.notifyCachedDabPainted(info); } void KisImagePipeBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX , double subPixelY, qreal softnessFactor) const { m_d->brushesPipe.generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } -QVector KisImagePipeBrush::brushes() const +QVector KisImagePipeBrush::brushes() const { return m_d->brushesPipe.brushes(); } KisFixedPaintDeviceSP KisImagePipeBrush::paintDevice( const KoColorSpace * colorSpace, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY) const { return m_d->brushesPipe.paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } enumBrushType KisImagePipeBrush::brushType() const { return !hasColor() || useColorAsMask() ? PIPE_MASK : PIPE_IMAGE; } bool KisImagePipeBrush::hasColor() const { return m_d->brushesPipe.hasColor(); } void KisImagePipeBrush::makeMaskImage() { m_d->brushesPipe.makeMaskImage(); setUseColorAsMask(false); } void KisImagePipeBrush::setUseColorAsMask(bool useColorAsMask) { - KisGbrBrush::setUseColorAsMask(useColorAsMask); + KisGimpBrush::setUseColorAsMask(useColorAsMask); m_d->brushesPipe.setUseColorAsMask(useColorAsMask); } const KisBoundary* KisImagePipeBrush::boundary() const { - KisGbrBrush *brush = m_d->brushesPipe.firstBrush(); + KisGimpBrush *brush = m_d->brushesPipe.firstBrush(); Q_ASSERT(brush); return brush->boundary(); } bool KisImagePipeBrush::canPaintFor(const KisPaintInformation& info) { return (!m_d->brushesPipe.parasite().needsMovement || info.drawingDistance() >= 0.5); } KisBrush* KisImagePipeBrush::clone() const { return new KisImagePipeBrush(*this); } QString KisImagePipeBrush::defaultFileExtension() const { return QString(".gih"); } quint32 KisImagePipeBrush::brushIndex(const KisPaintInformation& info) const { return m_d->brushesPipe.brushIndex(info); } qint32 KisImagePipeBrush::maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return m_d->brushesPipe.maskWidth(shape, subPixelX, subPixelY, info); } qint32 KisImagePipeBrush::maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return m_d->brushesPipe.maskHeight(shape, subPixelX, subPixelY, info); } void KisImagePipeBrush::setAngle(qreal _angle) { - KisGbrBrush::setAngle(_angle); + KisGimpBrush::setAngle(_angle); m_d->brushesPipe.setAngle(_angle); } void KisImagePipeBrush::setScale(qreal _scale) { - KisGbrBrush::setScale(_scale); + KisGimpBrush::setScale(_scale); m_d->brushesPipe.setScale(_scale); } void KisImagePipeBrush::setSpacing(double _spacing) { - KisGbrBrush::setSpacing(_spacing); + KisGimpBrush::setSpacing(_spacing); m_d->brushesPipe.setSpacing(_spacing); } void KisImagePipeBrush::setBrushType(enumBrushType type) { Q_UNUSED(type); qFatal("FATAL: protected member setBrushType has no meaning for KisImagePipeBrush"); // brushType() is a function of hasColor() and useColorAsMask() } void KisImagePipeBrush::setHasColor(bool hasColor) { Q_UNUSED(hasColor); qFatal("FATAL: protected member setHasColor has no meaning for KisImagePipeBrush"); // hasColor() is a function of the underlying brushes } -KisGbrBrush* KisImagePipeBrush::testingGetCurrentBrush(const KisPaintInformation& info) const +KisGimpBrush* KisImagePipeBrush::testingGetCurrentBrush(const KisPaintInformation& info) const { return m_d->brushesPipe.currentBrush(info); } void KisImagePipeBrush::testingSelectNextBrush(const KisPaintInformation& info) const { return m_d->brushesPipe.testingSelectNextBrush(info); } const KisPipeBrushParasite& KisImagePipeBrush::parasite() const { return m_d->brushesPipe.parasite(); } void KisImagePipeBrush::setParasite(const KisPipeBrushParasite ¶site) { m_d->brushesPipe.setParasite(parasite); } void KisImagePipeBrush::setDevices(QVector > devices, int w, int h) { for (int i = 0; i < devices.at(0).count(); i++) { - m_d->brushesPipe.addBrush(new KisGbrBrush(devices.at(0).at(i), 0, 0, w, h)); + m_d->brushesPipe.addBrush(new KisGimpBrush(devices.at(0).at(i), 0, 0, w, h)); } } diff --git a/libs/brush/kis_imagepipe_brush.h b/libs/brush/kis_imagepipe_brush.h index 208931fc7b..a8f3b2843e 100644 --- a/libs/brush/kis_imagepipe_brush.h +++ b/libs/brush/kis_imagepipe_brush.h @@ -1,142 +1,142 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Bart Coppens * * 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_IMAGEPIPE_BRUSH_ #define KIS_IMAGEPIPE_BRUSH_ #include #include #include #include -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_global.h" class KisPipeBrushParasite; /** * Velocity won't be supported, atm Tilt isn't either, * but have chances of implementation */ namespace KisParasite { enum SelectionMode { Constant, Incremental, Angular, Velocity, Random, Pressure, TiltX, TiltY }; } -class BRUSH_EXPORT KisImagePipeBrush : public KisGbrBrush +class BRUSH_EXPORT KisImagePipeBrush : public KisGimpBrush { public: KisImagePipeBrush(const QString& filename); /** * Specialized constructor that makes a new pipe brush from a sequence of samesize * devices. The fact that it's a vector of a vector, is to support multidimensional * brushes (not yet supported!) */ KisImagePipeBrush(const QString& name, int w, int h, QVector< QVector > devices, QVector modes); virtual ~KisImagePipeBrush(); virtual bool load(); virtual bool loadFromDevice(QIODevice *dev); virtual bool save(); virtual bool saveToDevice(QIODevice* dev) const; /** * @return the next image in the pipe. */ virtual KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0) const Q_DECL_OVERRIDE; virtual void setUseColorAsMask(bool useColorAsMask); virtual bool hasColor() const; virtual enumBrushType brushType() const; virtual const KisBoundary* boundary() const; virtual bool canPaintFor(const KisPaintInformation& info); virtual void makeMaskImage(); virtual KisBrush* clone() const; virtual QString defaultFileExtension() const; void setAngle(qreal _angle); void setScale(qreal _scale); void setSpacing(double _spacing); quint32 brushIndex(const KisPaintInformation& info) const Q_DECL_OVERRIDE; qint32 maskWidth(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const Q_DECL_OVERRIDE; qint32 maskHeight(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const Q_DECL_OVERRIDE; void notifyStrokeStarted(); void notifyCachedDabPainted(const KisPaintInformation& info); void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const Q_DECL_OVERRIDE; - QVector brushes() const; + QVector brushes() const; const KisPipeBrushParasite ¶site() const; void setParasite(const KisPipeBrushParasite& parasite); void setDevices(QVector< QVector > devices, int w, int h); protected: void setBrushType(enumBrushType type); void setHasColor(bool hasColor); /// Will call KisBrush's saveToDevice as well KisImagePipeBrush(const KisImagePipeBrush& rhs); private: friend class KisImagePipeBrushTest; - KisGbrBrush* testingGetCurrentBrush(const KisPaintInformation& info) const; + KisGimpBrush* testingGetCurrentBrush(const KisPaintInformation& info) const; void testingSelectNextBrush(const KisPaintInformation& info) const; bool initFromData(const QByteArray &data); private: struct Private; Private * const m_d; }; #endif // KIS_IMAGEPIPE_BRUSH_ diff --git a/libs/brush/kis_predefined_brush_factory.cpp b/libs/brush/kis_predefined_brush_factory.cpp index 4a2d32aa0a..931667ab36 100644 --- a/libs/brush/kis_predefined_brush_factory.cpp +++ b/libs/brush/kis_predefined_brush_factory.cpp @@ -1,82 +1,82 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * 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_predefined_brush_factory.h" #include #include "kis_brush_server.h" -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include KisPredefinedBrushFactory::KisPredefinedBrushFactory(const QString &brushType) : m_id(brushType) { } QString KisPredefinedBrushFactory::id() const { return m_id; } KisBrushSP KisPredefinedBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy) { KisBrushResourceServer *rServer = KisBrushServer::instance()->brushServer(); QString brushFileName = brushDefinition.attribute("filename", ""); KisBrushSP brush = rServer->resourceByFilename(brushFileName); //Fallback for files that still use the old format if (!brush) { QFileInfo info(brushFileName); brush = rServer->resourceByFilename(info.fileName()); } if (!brush) { brush = rServer->resources().first(); } Q_ASSERT(brush); if (forceCopy) { brush = brush->clone(); } double spacing = KisDomUtils::toDouble(brushDefinition.attribute("spacing", "0.25")); brush->setSpacing(spacing); bool useAutoSpacing = KisDomUtils::toInt(brushDefinition.attribute("useAutoSpacing", "0")); qreal autoSpacingCoeff = KisDomUtils::toDouble(brushDefinition.attribute("autoSpacingCoeff", "1.0")); brush->setAutoSpacing(useAutoSpacing, autoSpacingCoeff); double angle = KisDomUtils::toDouble(brushDefinition.attribute("angle", "0.0")); brush->setAngle(angle); double scale = KisDomUtils::toDouble(brushDefinition.attribute("scale", "1.0")); brush->setScale(scale); if (m_id == "gbr_brush") { - KisGbrBrush *gbrbrush = dynamic_cast(brush.data()); + KisGimpBrush *gbrbrush = dynamic_cast(brush.data()); if (gbrbrush) { /** - * WARNING: see comment in KisGbrBrush::setUseColorAsMask() + * WARNING: see comment in KisGimpBrush::setUseColorAsMask() */ gbrbrush->setUseColorAsMask((bool)brushDefinition.attribute("ColorAsMask").toInt()); } } return brush; } diff --git a/libs/brush/kis_qimage_pyramid.cpp b/libs/brush/kis_qimage_pyramid.cpp index f4818cbe17..1b0f7644f2 100644 --- a/libs/brush/kis_qimage_pyramid.cpp +++ b/libs/brush/kis_qimage_pyramid.cpp @@ -1,302 +1,302 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * 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_qimage_pyramid.h" #include #include #include #define MIPMAP_SIZE_THRESHOLD 512 #define MAX_MIPMAP_SCALE 8.0 #define QPAINTER_WORKAROUND_BORDER 1 KisQImagePyramid::KisQImagePyramid(const QImage &baseImage) { Q_ASSERT(!baseImage.isNull()); m_originalSize = baseImage.size(); qreal scale = MAX_MIPMAP_SCALE; while (scale > 1.0) { QSize scaledSize = m_originalSize * scale; if (scaledSize.width() <= MIPMAP_SIZE_THRESHOLD || scaledSize.height() <= MIPMAP_SIZE_THRESHOLD) { if (m_levels.isEmpty()) { m_baseScale = scale; } appendPyramidLevel(baseImage.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } scale *= 0.5; } if (m_levels.isEmpty()) { m_baseScale = 1.0; } appendPyramidLevel(baseImage); scale = 0.5; while (true) { QSize scaledSize = m_originalSize * scale; if (scaledSize.width() == 0 || scaledSize.height() == 0) break; appendPyramidLevel(baseImage.scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); scale *= 0.5; } } KisQImagePyramid::~KisQImagePyramid() { } int KisQImagePyramid::findNearestLevel(qreal scale, qreal *baseScale) const { const qreal scale_epsilon = 1e-6; qreal levelScale = m_baseScale; int level = 0; int lastLevel = m_levels.size() - 1; while ((0.5 * levelScale > scale || qAbs(0.5 * levelScale - scale) < scale_epsilon) && level < lastLevel) { levelScale *= 0.5; level++; } *baseScale = levelScale; return level; } inline QRect roundRect(const QRectF &rc) { /** * This is an analog of toAlignedRect() with the only difference * that it ensures the rect position will never be below zero. * * Warning: be *very* careful with using bottom()/right() values * of a pure QRect (we don't use it here for the dangers * it can lead to). */ QRectF rect(rc); KIS_ASSERT_RECOVER_NOOP(rect.x() > -1e-6); KIS_ASSERT_RECOVER_NOOP(rect.y() > -1e-6); if (rect.x() < 0.0) { rect.setLeft(0.0); } if (rect.y() < 0.0) { rect.setTop(0.0); } return rect.toAlignedRect(); } QTransform baseBrushTransform(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const QRectF &baseBounds) { QTransform transform; transform.scale(shape.scaleX(), shape.scaleY()); if (!qFuzzyCompare(shape.rotation(), 0)) { transform = transform * QTransform().rotateRadians(shape.rotation()); QRectF rotatedBounds = transform.mapRect(baseBounds); transform = transform * QTransform::fromTranslate(-rotatedBounds.x(), -rotatedBounds.y()); } return transform * QTransform::fromTranslate(subPixelX, subPixelY); } void KisQImagePyramid::calculateParams(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const QSize &originalSize, QTransform *outputTransform, QSize *outputSize) { calculateParams(shape, subPixelX, subPixelY, originalSize, 1.0, originalSize, outputTransform, outputSize); } void KisQImagePyramid::calculateParams(KisDabShape shape, qreal subPixelX, qreal subPixelY, const QSize &originalSize, qreal baseScale, const QSize &baseSize, QTransform *outputTransform, QSize *outputSize) { Q_UNUSED(baseScale); QRectF originalBounds = QRectF(QPointF(), originalSize); QTransform originalTransform = baseBrushTransform(shape, subPixelX, subPixelY, originalBounds); qreal realBaseScaleX = qreal(baseSize.width()) / originalSize.width(); qreal realBaseScaleY = qreal(baseSize.height()) / originalSize.height(); qreal scaleX = shape.scaleX() / realBaseScaleX; qreal scaleY = shape.scaleY() / realBaseScaleY; shape = KisDabShape(scaleX, scaleY/scaleX, shape.rotation()); QRectF baseBounds = QRectF(QPointF(), baseSize); QTransform transform = baseBrushTransform(shape, subPixelX, subPixelY, baseBounds); QRect expectedDstRect = roundRect(originalTransform.mapRect(originalBounds)); #if 0 // Only enable when debugging; users shouldn't see this warning { QRect testingRect = roundRect(transform.mapRect(baseBounds)); if (testingRect != expectedDstRect) { warnKrita << "WARNING: expected and real dab rects do not coincide!"; warnKrita << " expected rect:" << expectedDstRect; warnKrita << " real rect: " << testingRect; } } #endif KIS_ASSERT_RECOVER_NOOP(expectedDstRect.x() >= 0); KIS_ASSERT_RECOVER_NOOP(expectedDstRect.y() >= 0); int width = expectedDstRect.x() + expectedDstRect.width(); int height = expectedDstRect.y() + expectedDstRect.height(); // we should not return invalid image, so adjust the image to be // at least 1 px in size. width = qMax(1, width); height = qMax(1, height); *outputTransform = transform; *outputSize = QSize(width, height); } QSize KisQImagePyramid::imageSize(const QSize &originalSize, KisDabShape const& shape, qreal subPixelX, qreal subPixelY) { QTransform transform; QSize dstSize; calculateParams(shape, subPixelX, subPixelY, originalSize, &transform, &dstSize); return dstSize; } QSizeF KisQImagePyramid::characteristicSize(const QSize &originalSize, KisDabShape const& shape) { QRectF originalRect(QPointF(), originalSize); QTransform transform = baseBrushTransform(shape, 0.0, 0.0, originalRect); return transform.mapRect(originalRect).size(); } void KisQImagePyramid::appendPyramidLevel(const QImage &image) { /** * QPainter has a bug: when doing a transformation it decides that * all the pixels outside of the image (source rect) are equal to * the border pixels (CLAMP in terms of openGL). This means that * there will be no smooth scaling on the border of the image when * it is rotated. To workaround this bug we need to add one pixel * wide border to the image, so that it transforms smoothly. * - * See a unittest in: KisGbrBrushTest::testQPainterTransformationBorder + * See a unittest in: KisGimpBrushTest::testQPainterTransformationBorder */ QSize levelSize = image.size(); QImage tmp = image.convertToFormat(QImage::Format_ARGB32); tmp = tmp.copy(-QPAINTER_WORKAROUND_BORDER, -QPAINTER_WORKAROUND_BORDER, image.width() + 2 * QPAINTER_WORKAROUND_BORDER, image.height() + 2 * QPAINTER_WORKAROUND_BORDER); m_levels.append(PyramidLevel(tmp, levelSize)); } QImage KisQImagePyramid::createImage(KisDabShape const& shape, qreal subPixelX, qreal subPixelY) const { qreal baseScale = -1.0; int level = findNearestLevel(shape.scale(), &baseScale); const QImage &srcImage = m_levels[level].image; QTransform transform; QSize dstSize; calculateParams(shape, subPixelX, subPixelY, m_originalSize, baseScale, m_levels[level].size, &transform, &dstSize); if (transform.isIdentity() && srcImage.format() == QImage::Format_ARGB32) { return srcImage.copy(QPAINTER_WORKAROUND_BORDER, QPAINTER_WORKAROUND_BORDER, srcImage.width() - 2 * QPAINTER_WORKAROUND_BORDER, srcImage.height() - 2 * QPAINTER_WORKAROUND_BORDER); } QImage dstImage(dstSize, QImage::Format_ARGB32); dstImage.fill(0); /** * QPainter has one more bug: when a QTransform is TxTranslate, it * does wrong sampling (probably, Nearest Neighbour) even though * we tell it directly that we need SmoothPixmapTransform. * * So here is a workaround: we set a negligible scale to convince * Qt we use a non-only-translating transform. */ while (transform.type() == QTransform::TxTranslate) { const qreal scale = transform.m11(); const qreal fakeScale = scale - 10 * std::numeric_limits::epsilon(); transform *= QTransform::fromScale(fakeScale, fakeScale); } QPainter gc(&dstImage); gc.setTransform( QTransform::fromTranslate(-QPAINTER_WORKAROUND_BORDER, -QPAINTER_WORKAROUND_BORDER) * transform); gc.setRenderHints(QPainter::SmoothPixmapTransform); gc.drawImage(QPointF(), srcImage); gc.end(); return dstImage; } diff --git a/libs/brush/kis_qimage_pyramid.h b/libs/brush/kis_qimage_pyramid.h index 1086a3e9d8..30981ae6e3 100644 --- a/libs/brush/kis_qimage_pyramid.h +++ b/libs/brush/kis_qimage_pyramid.h @@ -1,74 +1,74 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * 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_QIMAGE_PYRAMID_H #define __KIS_QIMAGE_PYRAMID_H #include #include #include #include class BRUSH_EXPORT KisQImagePyramid { public: KisQImagePyramid(const QImage &baseImage); ~KisQImagePyramid(); static QSize imageSize(const QSize &originalSize, KisDabShape const&, qreal subPixelX, qreal subPixelY); static QSizeF characteristicSize(const QSize &originalSize, KisDabShape const&); QImage createImage(KisDabShape const&, qreal subPixelX, qreal subPixelY) const; private: - friend class KisGbrBrushTest; + friend class KisGimpBrushTest; int findNearestLevel(qreal scale, qreal *baseScale) const; void appendPyramidLevel(const QImage &image); static void calculateParams(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const QSize &originalSize, QTransform *outputTransform, QSize *outputSize); static void calculateParams(KisDabShape shape, qreal subPixelX, qreal subPixelY, const QSize &originalSize, qreal baseScale, const QSize &baseSize, QTransform *outputTransform, QSize *outputSize); private: QSize m_originalSize; qreal m_baseScale; struct PyramidLevel { PyramidLevel() {} PyramidLevel(QImage _image, QSize _size) : image(_image), size(_size) {} QImage image; QSize size; }; QVector m_levels; }; #endif /* __KIS_QIMAGE_PYRAMID_H */ diff --git a/libs/brush/kis_text_brush.cpp b/libs/brush/kis_text_brush.cpp index d95ea9b782..0a5b2603bc 100644 --- a/libs/brush/kis_text_brush.cpp +++ b/libs/brush/kis_text_brush.cpp @@ -1,310 +1,310 @@ /* * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2011 Lukáš Tvrdý * * 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_text_brush.h" #include #include #include #include -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_brushes_pipe.h" #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND #include #include #include #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ -class KisTextBrushesPipe : public KisBrushesPipe +class KisTextBrushesPipe : public KisBrushesPipe { public: KisTextBrushesPipe() { m_charIndex = 0; m_currentBrushIndex = 0; } KisTextBrushesPipe(const KisTextBrushesPipe &rhs) - : KisBrushesPipe(rhs) { + : KisBrushesPipe(rhs) { m_brushesMap.clear(); - QMapIterator iter(rhs.m_brushesMap); + QMapIterator iter(rhs.m_brushesMap); while (iter.hasNext()) { iter.next(); m_brushesMap.insert(iter.key(), iter.value()); } } void setText(const QString &text, const QFont &font) { m_text = text; m_charIndex = 0; clear(); for (int i = 0; i < m_text.length(); i++) { QChar letter = m_text.at(i); QImage image = renderChar(letter, font); - KisGbrBrush *brush = new KisGbrBrush(image, letter); + KisGimpBrush *brush = new KisGimpBrush(image, letter); brush->setSpacing(0.1); // support for letter spacing? brush->makeMaskImage(); m_brushesMap.insert(letter, brush); - KisBrushesPipe::addBrush(brush); + KisBrushesPipe::addBrush(brush); } } static QImage renderChar(const QString& text, const QFont &font) { #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND QWidget *focusWidget = qApp->focusWidget(); if (focusWidget) { QThread *guiThread = focusWidget->thread(); if (guiThread != QThread::currentThread()) { warnKrita << "WARNING: Rendering text in non-GUI thread!" << "That may lead to hangups and crashes on some" << "versions of X11/Qt!"; } } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ QFontMetrics metric(font); QRect rect = metric.boundingRect(text); if (rect.isEmpty()) { rect = QRect(0, 0, 1, 1); // paint at least something } QRect paintingRect = rect.translated(-rect.x(), -rect.y()); QImage renderedChar(paintingRect.size(), QImage::Format_ARGB32); QPainter p; p.begin(&renderedChar); p.setFont(font); p.fillRect(paintingRect, Qt::white); p.setPen(Qt::black); p.drawText(-rect.x(), -rect.y(), text); p.end(); return renderedChar; } void clear() { m_brushesMap.clear(); - KisBrushesPipe::clear(); + KisBrushesPipe::clear(); } - KisGbrBrush* firstBrush() const { + KisGimpBrush* firstBrush() const { Q_ASSERT(m_text.size() > 0); Q_ASSERT(m_brushesMap.size() > 0); return m_brushesMap.value(m_text.at(0)); } void notifyStrokeStarted() { m_charIndex = 0; updateBrushIndexesImpl(); } protected: int chooseNextBrush(const KisPaintInformation& info) { Q_UNUSED(info); return m_currentBrushIndex; } void updateBrushIndexes(const KisPaintInformation& info) { Q_UNUSED(info); m_charIndex++; updateBrushIndexesImpl(); } private: void updateBrushIndexesImpl() { if (m_text.isEmpty()) return; if (m_charIndex >= m_text.size()) { m_charIndex = 0; } QChar letter = m_text.at(m_charIndex); Q_ASSERT(m_brushesMap.contains(letter)); m_currentBrushIndex = m_brushes.indexOf(m_brushesMap.value(letter)); } private: - QMap m_brushesMap; + QMap m_brushesMap; QString m_text; int m_charIndex; int m_currentBrushIndex; }; KisTextBrush::KisTextBrush() : m_brushesPipe(new KisTextBrushesPipe()) { setPipeMode(false); } KisTextBrush::KisTextBrush(const KisTextBrush &rhs) : KisScalingSizeBrush(rhs), m_brushesPipe(new KisTextBrushesPipe(*rhs.m_brushesPipe)) { } KisTextBrush::~KisTextBrush() { delete m_brushesPipe; } void KisTextBrush::setPipeMode(bool pipe) { setBrushType(pipe ? PIPE_MASK : MASK); } bool KisTextBrush::pipeMode() const { return brushType() == PIPE_MASK; } void KisTextBrush::setText(const QString& txt) { m_text = txt; } QString KisTextBrush::text(void) const { return m_text; } void KisTextBrush::setFont(const QFont& font) { m_font = font; } QFont KisTextBrush::font() { return m_font; } void KisTextBrush::notifyStrokeStarted() { m_brushesPipe->notifyStrokeStarted(); } void KisTextBrush::notifyCachedDabPainted(const KisPaintInformation& info) { m_brushesPipe->notifyCachedDabPainted(info); } void KisTextBrush::generateMaskAndApplyMaskOrCreateDab( KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor) const { if (brushType() == MASK) { KisBrush::generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } else { /* if (brushType() == PIPE_MASK)*/ m_brushesPipe->generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } } KisFixedPaintDeviceSP KisTextBrush::paintDevice(const KoColorSpace * colorSpace, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY) const { if (brushType() == MASK) { return KisBrush::paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } else { /* if (brushType() == PIPE_MASK)*/ return m_brushesPipe->paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } } void KisTextBrush::toXML(QDomDocument& doc, QDomElement& e) const { Q_UNUSED(doc); e.setAttribute("type", "kis_text_brush"); e.setAttribute("spacing", KisDomUtils::toString(spacing())); e.setAttribute("text", m_text); e.setAttribute("font", m_font.toString()); e.setAttribute("pipe", (brushType() == PIPE_MASK) ? "true" : "false"); KisBrush::toXML(doc, e); } void KisTextBrush::updateBrush() { Q_ASSERT((brushType() == PIPE_MASK) || (brushType() == MASK)); if (brushType() == PIPE_MASK) { m_brushesPipe->setText(m_text, m_font); setBrushTipImage(m_brushesPipe->firstBrush()->brushTipImage()); } else { /* if (brushType() == MASK)*/ setBrushTipImage(KisTextBrushesPipe::renderChar(m_text, m_font)); } resetBoundary(); setValid(true); } quint32 KisTextBrush::brushIndex(const KisPaintInformation& info) const { return brushType() == MASK ? 0 : 1 + m_brushesPipe->brushIndex(info); } qint32 KisTextBrush::maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return brushType() == MASK ? KisBrush::maskWidth(shape, subPixelX, subPixelY, info) : m_brushesPipe->maskWidth(shape, subPixelX, subPixelY, info); } qint32 KisTextBrush::maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return brushType() == MASK ? KisBrush::maskHeight(shape, subPixelX, subPixelY, info) : m_brushesPipe->maskHeight(shape, subPixelX, subPixelY, info); } void KisTextBrush::setAngle(qreal _angle) { KisBrush::setAngle(_angle); m_brushesPipe->setAngle(_angle); } void KisTextBrush::setScale(qreal _scale) { KisBrush::setScale(_scale); m_brushesPipe->setScale(_scale); } void KisTextBrush::setSpacing(double _spacing) { KisBrush::setSpacing(_spacing); m_brushesPipe->setSpacing(_spacing); } KisBrush* KisTextBrush::clone() const { return new KisTextBrush(*this); } diff --git a/libs/brush/tests/CMakeLists.txt b/libs/brush/tests/CMakeLists.txt index 4e84636983..d65b505f4a 100644 --- a/libs/brush/tests/CMakeLists.txt +++ b/libs/brush/tests/CMakeLists.txt @@ -1,44 +1,44 @@ ########### next target ############### set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) include_directories( ${CMAKE_SOURCE_DIR}/libs/image/metadata ${CMAKE_SOURCE_DIR}/sdk/tests ) include_directories(SYSTEM ${EIGEN3_INCLUDE_DIR} ) if(HAVE_VC) include_directories(SYSTEM ${Vc_INCLUDE_DIR} ) endif() macro_add_unittest_definitions() ########### next target ############### set(kis_auto_brush_test_SRCS kis_auto_brush_test.cpp ) kde4_add_unit_test(KisAutoBrushTest TESTNAME krita-libbrush-KisAutoBrushTest ${kis_auto_brush_test_SRCS}) target_link_libraries(KisAutoBrushTest kritaimage kritalibbrush Qt5::Test) ########### next target ############### -set(kis_gbr_brush_test_SRCS kis_gbr_brush_test.cpp ) -kde4_add_unit_test(KisGbrBrushTest TESTNAME krita-libbrush-KisGbrBrushTest ${kis_gbr_brush_test_SRCS}) -target_link_libraries(KisGbrBrushTest kritaimage kritalibbrush Qt5::Test) +set(kis_gimp_brush_test_SRCS kis_gimp_brush_test.cpp ) +kde4_add_unit_test(KisGimpBrushTest TESTNAME krita-libbrush-KisGimpBrushTest ${kis_gimp_brush_test_SRCS}) +target_link_libraries(KisGimpBrushTest kritaimage kritalibbrush Qt5::Test) ########### next target ############### set(kis_boundary_test_SRCS kis_boundary_test.cpp ) kde4_add_unit_test(KisBoundaryTest TESTNAME krita-libbrush-KisBoundaryTest ${kis_boundary_test_SRCS}) target_link_libraries(KisBoundaryTest kritaimage kritalibbrush Qt5::Test) ########### next target ############### set(kis_imagepipe_brush_test_SRCS kis_imagepipe_brush_test.cpp ) kde4_add_unit_test(KisImagePipeBrushTest TESTNAME krita-libbrush-KisImagePipeBrushTest ${kis_imagepipe_brush_test_SRCS}) target_link_libraries(KisImagePipeBrushTest kritaimage kritalibbrush Qt5::Test) diff --git a/libs/brush/tests/kis_gbr_brush_test.cpp b/libs/brush/tests/kis_gimp_brush_test.cpp similarity index 84% rename from libs/brush/tests/kis_gbr_brush_test.cpp rename to libs/brush/tests/kis_gimp_brush_test.cpp index c027e9dc88..e4cb762346 100644 --- a/libs/brush/tests/kis_gbr_brush_test.cpp +++ b/libs/brush/tests/kis_gimp_brush_test.cpp @@ -1,361 +1,361 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "kis_gbr_brush_test.h" +#include "kis_gimp_brush_test.h" #include #include #include #include #include #include #include "testutil.h" -#include "../kis_gbr_brush.h" +#include "../kis_gimp_brush.h" #include "kis_types.h" #include "kis_paint_device.h" #include "brushengine/kis_paint_information.h" #include #include "kis_qimage_pyramid.h" -void KisGbrBrushTest::testMaskGenerationNoColor() +void KisGimpBrushTest::testMaskGenerationNoColor() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); brush->load(); Q_ASSERT(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); // check masking an existing paint device KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs); fdev->setRect(QRect(0, 0, 100, 100)); fdev->initialize(); cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100); QPoint errpoint; QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "result_brush_1.png"); QImage image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { - image.save("kis_gbr_brush_test_1.png"); + image.save("kis_gimp_brush_test_1.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } brush->mask(fdev, KisDabShape(), info); result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_brush_2.png"); image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { - image.save("kis_gbr_brush_test_2.png"); + image.save("kis_gimp_brush_test_2.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } -void KisGbrBrushTest::testMaskGenerationSingleColor() +void KisGimpBrushTest::testMaskGenerationSingleColor() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); brush->load(); Q_ASSERT(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); // check masking an existing paint device KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs); fdev->setRect(QRect(0, 0, 100, 100)); fdev->initialize(); cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100); // Check creating a mask dab with a single color fdev = new KisFixedPaintDevice(cs); brush->mask(fdev, KoColor(Qt::black, cs), KisDabShape(), info); QPoint errpoint; QImage result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_brush_3.png"); QImage image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { - image.save("kis_gbr_brush_test_3.png"); + image.save("kis_gimp_brush_test_3.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } -void KisGbrBrushTest::testMaskGenerationDevColor() +void KisGimpBrushTest::testMaskGenerationDevColor() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); brush->load(); Q_ASSERT(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); // check masking an existing paint device KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs); fdev->setRect(QRect(0, 0, 100, 100)); fdev->initialize(); cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100); // Check creating a mask dab with a color taken from a paint device KoColor red(Qt::red, cs); cs->setOpacity(red.data(), quint8(128), 1); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->fill(0, 0, 100, 100, red.data()); fdev = new KisFixedPaintDevice(cs); brush->mask(fdev, dev, KisDabShape(), info); QPoint errpoint; QImage result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_brush_4.png"); QImage image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { - image.save("kis_gbr_brush_test_4.png"); + image.save("kis_gimp_brush_test_4.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } -void KisGbrBrushTest::testMaskGenerationDefaultColor() +void KisGimpBrushTest::testMaskGenerationDefaultColor() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "brush.gbr"); brush->load(); Q_ASSERT(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); // check masking an existing paint device KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs); fdev->setRect(QRect(0, 0, 100, 100)); fdev->initialize(); cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100); // check creating a mask dab with a default color fdev = new KisFixedPaintDevice(cs); brush->mask(fdev, KisDabShape(), info); QPoint errpoint; QImage result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_brush_3.png"); QImage image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { - image.save("kis_gbr_brush_test_5.png"); + image.save("kis_gimp_brush_test_5.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } delete brush; } -void KisGbrBrushTest::testImageGeneration() +void KisGimpBrushTest::testImageGeneration() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); bool res = brush->load(); Q_UNUSED(res); Q_ASSERT(res); QVERIFY(!brush->brushTipImage().isNull()); brush->prepareBrushPyramid(); qsrand(1); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisFixedPaintDeviceSP dab; for (int i = 0; i < 200; i++) { qreal scale = qreal(qrand()) / RAND_MAX * 2.0; qreal rotation = qreal(qrand()) / RAND_MAX * 2 * M_PI; qreal subPixelX = qreal(qrand()) / RAND_MAX * 0.5; QString testName = QString("brush_%1_sc_%2_rot_%3_sub_%4") .arg(i).arg(scale).arg(rotation).arg(subPixelX); dab = brush->paintDevice(cs, KisDabShape(scale, 1.0, rotation), info, subPixelX); /** * Compare first 10 images. Others are tested for asserts only */ if (i < 10) { QImage result = dab->convertToQImage(0); TestUtil::checkQImage(result, "brush_masks", "", testName); } } } -void KisGbrBrushTest::benchmarkPyramidCreation() +void KisGimpBrushTest::benchmarkPyramidCreation() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); brush->load(); QVERIFY(!brush->brushTipImage().isNull()); QBENCHMARK { brush->prepareBrushPyramid(); brush->clearBrushPyramid(); } } -void KisGbrBrushTest::benchmarkScaling() +void KisGimpBrushTest::benchmarkScaling() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); brush->load(); QVERIFY(!brush->brushTipImage().isNull()); brush->prepareBrushPyramid(); qsrand(1); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisFixedPaintDeviceSP dab; QBENCHMARK { dab = brush->paintDevice(cs, KisDabShape(qreal(qrand()) / RAND_MAX * 2.0, 1.0, 0.0), info); //dab->convertToQImage(0).save(QString("dab_%1_new_smooth.png").arg(i++)); } } -void KisGbrBrushTest::benchmarkRotation() +void KisGimpBrushTest::benchmarkRotation() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); brush->load(); QVERIFY(!brush->brushTipImage().isNull()); brush->prepareBrushPyramid(); qsrand(1); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisFixedPaintDeviceSP dab; QBENCHMARK { dab = brush->paintDevice(cs, KisDabShape(1.0, 1.0, qreal(qrand()) / RAND_MAX * 2 * M_PI), info); } } -void KisGbrBrushTest::benchmarkMaskScaling() +void KisGimpBrushTest::benchmarkMaskScaling() { - KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); + KisGimpBrush* brush = new KisGimpBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"); brush->load(); QVERIFY(!brush->brushTipImage().isNull()); brush->prepareBrushPyramid(); qsrand(1); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisFixedPaintDeviceSP dab = new KisFixedPaintDevice(cs); QBENCHMARK { KoColor c(Qt::black, cs); qreal scale = qreal(qrand()) / RAND_MAX * 2.0; brush->mask(dab, c, KisDabShape(scale, 1.0, 0.0), info, 0.0, 0.0, 1.0); } } -void KisGbrBrushTest::testPyramidLevelRounding() +void KisGimpBrushTest::testPyramidLevelRounding() { QSize imageSize(41, 41); QImage image(imageSize, QImage::Format_ARGB32); image.fill(0); KisQImagePyramid pyramid(image); qreal baseScale; int baseLevel; baseLevel = pyramid.findNearestLevel(1.0, &baseScale); QCOMPARE(baseScale, 1.0); QCOMPARE(baseLevel, 3); baseLevel = pyramid.findNearestLevel(2.0, &baseScale); QCOMPARE(baseScale, 2.0); QCOMPARE(baseLevel, 2); baseLevel = pyramid.findNearestLevel(4.0, &baseScale); QCOMPARE(baseScale, 4.0); QCOMPARE(baseLevel, 1); baseLevel = pyramid.findNearestLevel(0.5, &baseScale); QCOMPARE(baseScale, 0.5); QCOMPARE(baseLevel, 4); baseLevel = pyramid.findNearestLevel(0.25, &baseScale); QCOMPARE(baseScale, 0.25); QCOMPARE(baseLevel, 5); baseLevel = pyramid.findNearestLevel(0.25 + 1e-7, &baseScale); QCOMPARE(baseScale, 0.25); QCOMPARE(baseLevel, 5); } static QSize dabTransformHelper(KisDabShape const& shape) { QSize const testSize(150, 150); qreal const subPixelX = 0.0, subPixelY = 0.0; return KisQImagePyramid::imageSize(testSize, shape, subPixelX, subPixelY); } -void KisGbrBrushTest::testPyramidDabTransform() +void KisGimpBrushTest::testPyramidDabTransform() { QCOMPARE(dabTransformHelper(KisDabShape(1.0, 1.0, 0.0)), QSize(150, 150)); QCOMPARE(dabTransformHelper(KisDabShape(1.0, 0.5, 0.0)), QSize(150, 75)); QCOMPARE(dabTransformHelper(KisDabShape(1.0, 1.0, M_PI / 4)), QSize(213, 213)); QCOMPARE(dabTransformHelper(KisDabShape(1.0, 0.5, M_PI / 4)), QSize(160, 160)); } // see comment in KisQImagePyramid::appendPyramidLevel -void KisGbrBrushTest::testQPainterTransformationBorder() +void KisGimpBrushTest::testQPainterTransformationBorder() { QImage image1(10, 10, QImage::Format_ARGB32); QImage image2(12, 12, QImage::Format_ARGB32); image1.fill(0); image2.fill(0); { QPainter gc(&image1); gc.fillRect(QRect(0, 0, 10, 10), Qt::black); } { QPainter gc(&image2); gc.fillRect(QRect(1, 1, 10, 10), Qt::black); } image1.save("src1.png"); image2.save("src2.png"); { QImage canvas(100, 100, QImage::Format_ARGB32); canvas.fill(0); QPainter gc(&canvas); QTransform transform; transform.rotate(15); gc.setTransform(transform); gc.setRenderHints(QPainter::SmoothPixmapTransform); gc.drawImage(QPointF(50, 50), image1); gc.end(); canvas.save("canvas1.png"); } { QImage canvas(100, 100, QImage::Format_ARGB32); canvas.fill(0); QPainter gc(&canvas); QTransform transform; transform.rotate(15); gc.setTransform(transform); gc.setRenderHints(QPainter::SmoothPixmapTransform); gc.drawImage(QPointF(50, 50), image2); gc.end(); canvas.save("canvas2.png"); } } -QTEST_MAIN(KisGbrBrushTest) +QTEST_MAIN(KisGimpBrushTest) diff --git a/libs/brush/tests/kis_gbr_brush_test.h b/libs/brush/tests/kis_gimp_brush_test.h similarity index 97% rename from libs/brush/tests/kis_gbr_brush_test.h rename to libs/brush/tests/kis_gimp_brush_test.h index 070a03b3b7..5fa16e4c6c 100644 --- a/libs/brush/tests/kis_gbr_brush_test.h +++ b/libs/brush/tests/kis_gimp_brush_test.h @@ -1,49 +1,49 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_BRUSH_TEST_H #define KIS_BRUSH_TEST_H #include -class KisGbrBrushTest : public QObject +class KisGimpBrushTest : public QObject { Q_OBJECT // XXX disabled until I figure out why they don't work from here, while the brushes do work from Krita void testMaskGenerationNoColor(); void testMaskGenerationSingleColor(); void testMaskGenerationDevColor(); void testMaskGenerationDefaultColor(); private Q_SLOTS: void testImageGeneration(); void benchmarkPyramidCreation(); void benchmarkScaling(); void benchmarkRotation(); void benchmarkMaskScaling(); void testPyramidLevelRounding(); void testPyramidDabTransform(); void testQPainterTransformationBorder(); }; #endif diff --git a/libs/brush/tests/kis_imagepipe_brush_test.cpp b/libs/brush/tests/kis_imagepipe_brush_test.cpp index ea47af1816..58f7554205 100644 --- a/libs/brush/tests/kis_imagepipe_brush_test.cpp +++ b/libs/brush/tests/kis_imagepipe_brush_test.cpp @@ -1,278 +1,278 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * 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_imagepipe_brush_test.h" #include #include #include #include #include #include #include #include #include "kis_imagepipe_brush.h" #include #include #define COMPARE_ALL(brush, method) \ - Q_FOREACH (KisGbrBrush *child, brush->brushes()) { \ + Q_FOREACH (KisGimpBrush *child, brush->brushes()) { \ if(brush->method() != child->method()) { \ dbgKrita << "Failing method:" << #method \ << "brush index:" \ << brush->brushes().indexOf(child); \ QCOMPARE(brush->method(), child->method()); \ } \ } inline void KisImagePipeBrushTest::checkConsistency(KisImagePipeBrush *brush) { qreal scale = 0.5; Q_UNUSED(scale); - KisGbrBrush *firstBrush = brush->brushes().first(); + KisGimpBrush *firstBrush = brush->brushes().first(); /** * This set of values is supposed to be constant, so * it is just set to the corresponding values of the * first brush */ QCOMPARE(brush->width(), firstBrush->width()); QCOMPARE(brush->height(), firstBrush->height()); QCOMPARE(brush->boundary(), firstBrush->boundary()); /** * These values should be spread over the children brushes */ COMPARE_ALL(brush, maskAngle); COMPARE_ALL(brush, scale); COMPARE_ALL(brush, angle); COMPARE_ALL(brush, spacing); /** * Check mask size values, they depend on current brush */ KisPaintInformation info; KisBrush *oldBrush = brush->testingGetCurrentBrush(info); QVERIFY(oldBrush); qreal realScale = 1; qreal realAngle = 0; qreal subPixelX = 0; qreal subPixelY = 0; int maskWidth = brush->maskWidth(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); int maskHeight = brush->maskHeight(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KisFixedPaintDeviceSP dev = brush->testingGetCurrentBrush(info)->paintDevice( cs, KisDabShape(realScale, 1.0, realAngle), info, subPixelX, subPixelY); QCOMPARE(maskWidth, dev->bounds().width()); QCOMPARE(maskHeight, dev->bounds().height()); KisBrush *newBrush = brush->testingGetCurrentBrush(info); QCOMPARE(oldBrush, newBrush); } void KisImagePipeBrushTest::testLoading() { KisImagePipeBrush *brush = new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih"); brush->load(); QVERIFY(brush->valid()); checkConsistency(brush); delete brush; } void KisImagePipeBrushTest::testChangingBrushes() { KisImagePipeBrush *brush = new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih"); brush->load(); QVERIFY(brush->valid()); qreal rotation = 0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); for (int i = 0; i < 100; i++) { checkConsistency(brush); brush->testingSelectNextBrush(info); } delete brush; } void checkIncrementalPainting(KisBrush *brush, const QString &prefix) { qreal realScale = 1; qreal realAngle = 0; const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor fillColor(Qt::red, cs); KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(cs); qreal rotation = 0; qreal subPixelX = 0.0; qreal subPixelY = 0.0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); for (int i = 0; i < 20; i++) { int maskWidth = brush->maskWidth(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); int maskHeight = brush->maskHeight(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); QRect fillRect(0, 0, maskWidth, maskHeight); fixedDab->setRect(fillRect); fixedDab->initialize(); fixedDab->fill(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), fillColor.data()); brush->mask(fixedDab, KisDabShape(realScale, 1.0, realAngle), info); QCOMPARE(fixedDab->bounds(), fillRect); QImage result = fixedDab->convertToQImage(0); result.save(QString("fixed_dab_%1_%2.png").arg(prefix).arg(i)); } } void KisImagePipeBrushTest::testSimpleDabApplication() { KisImagePipeBrush *brush = new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih"); brush->load(); QVERIFY(brush->valid()); checkConsistency(brush); checkIncrementalPainting(brush, "simple"); delete brush; } void KisImagePipeBrushTest::testColoredDab() { KisImagePipeBrush *brush = new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih"); brush->load(); QVERIFY(brush->valid()); checkConsistency(brush); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_IMAGE); // let it be the mask (should be revertible) brush->setUseColorAsMask(true); QCOMPARE(brush->useColorAsMask(), true); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_MASK); // revert back brush->setUseColorAsMask(false); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_IMAGE); // convert to the mask (irreversible) brush->makeMaskImage(); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), false); QCOMPARE(brush->brushType(), PIPE_MASK); checkConsistency(brush); delete brush; } void KisImagePipeBrushTest::testColoredDabWash() { KisImagePipeBrush *brush = new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih"); brush->load(); QVERIFY(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); qreal rotation = 0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); KisPaintDeviceSP layer = new KisPaintDevice(cs); KisPainter painter(layer); painter.setCompositeOp(COMPOSITE_ALPHA_DARKEN); - const QVector gbrs = brush->brushes(); + const QVector gbrs = brush->brushes(); KisFixedPaintDeviceSP dab = gbrs.at(0)->paintDevice(cs, KisDabShape(2.0, 1.0, 0.0), info); painter.bltFixed(0, 0, dab, 0, 0, dab->bounds().width(), dab->bounds().height()); painter.bltFixed(80, 60, dab, 0, 0, dab->bounds().width(), dab->bounds().height()); painter.end(); QRect rc = layer->exactBounds(); QImage result = layer->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height()); #if 0 // if you want to see the result on white background, set #if 1 QImage bg(result.size(), result.format()); bg.fill(Qt::white); QPainter qPainter(&bg); qPainter.drawImage(0, 0, result); result = bg; #endif result.save("z_spark_alpha_darken.png"); delete brush; } #include "kis_text_brush.h" void KisImagePipeBrushTest::testTextBrushNoPipes() { KisTextBrush *brush = new KisTextBrush(); brush->setPipeMode(false); brush->setFont(QApplication::font()); brush->setText("The_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog"); brush->updateBrush(); checkIncrementalPainting(brush, "text_no_incremental"); delete brush; } void KisImagePipeBrushTest::testTextBrushPiped() { KisTextBrush *brush = new KisTextBrush(); brush->setPipeMode(true); brush->setFont(QApplication::font()); brush->setText("The_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog"); brush->updateBrush(); checkIncrementalPainting(brush, "text_incremental"); delete brush; } QTEST_MAIN(KisImagePipeBrushTest) diff --git a/plugins/impex/brush/kis_brush_export.cpp b/plugins/impex/brush/kis_brush_export.cpp index 99faa90a5a..0cef25efd1 100644 --- a/plugins/impex/brush/kis_brush_export.cpp +++ b/plugins/impex/brush/kis_brush_export.cpp @@ -1,213 +1,213 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * 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_brush_export.h" #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include struct KisBrushExportOptions { qreal spacing; bool mask; int brushStyle; int selectionMode; QString name; }; K_PLUGIN_FACTORY_WITH_JSON(KisBrushExportFactory, "krita_brush_export.json", registerPlugin();) KisBrushExport::KisBrushExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBrushExport::~KisBrushExport() { } KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(configuration); KisDocument *input = inputDocument(); QString filename = outputFile(); if (!input) return KisImportExportFilter::NoDocumentCreated; if (filename.isEmpty()) return KisImportExportFilter::FileNotFound; if (from != "application/x-krita") return KisImportExportFilter::NotImplemented; KisAnnotationSP annotation = input->image()->annotation("ImagePipe Parasite"); KisPipeBrushParasite parasite; if (annotation) { QBuffer buf(const_cast(&annotation->annotation())); buf.open(QBuffer::ReadOnly); //parasite.loadFromDevice(&buf); buf.close(); } KisBrushExportOptions exportOptions; exportOptions.spacing = 1.0; exportOptions.name = input->image()->objectName(); exportOptions.mask = true; exportOptions.selectionMode = 0; exportOptions.brushStyle = 0; if (input->image()->dynamicPropertyNames().contains("brushspacing")) { exportOptions.spacing = input->image()->property("brushspacing").toFloat(); } - KisGbrBrush *brush = 0; + KisGimpBrush *brush = 0; if (!getBatchMode()) { KoDialog* dlgBrushExportOptions = new KoDialog(0); dlgBrushExportOptions->setWindowTitle(i18n("Brush Tip Export Options")); dlgBrushExportOptions->setButtons(KoDialog::Ok | KoDialog::Cancel); Ui::WdgExportGih wdgUi; QWidget* wdg = new QWidget(dlgBrushExportOptions); wdgUi.setupUi(wdg); wdgUi.spacingWidget->setSpacing(false, exportOptions.spacing); wdgUi.nameLineEdit->setText(exportOptions.name); dlgBrushExportOptions->setMainWidget(wdg); if (to == "image/x-gimp-brush") { - brush = new KisGbrBrush(filename); + brush = new KisGimpBrush(filename); wdgUi.groupBox->setVisible(false); } else if (to == "image/x-gimp-brush-animated") { brush = new KisImagePipeBrush(filename); wdgUi.groupBox->setVisible(true); } else { delete dlgBrushExportOptions; return KisImportExportFilter::BadMimeType; } if (dlgBrushExportOptions->exec() == QDialog::Rejected) { delete dlgBrushExportOptions; return KisImportExportFilter::UserCancelled; } else { exportOptions.spacing = wdgUi.spacingWidget->spacing(); exportOptions.name = wdgUi.brushNameLbl->text(); exportOptions.mask = wdgUi.colorAsMask->isChecked(); exportOptions.brushStyle = wdgUi.brushStyle->currentIndex(); exportOptions.selectionMode = wdgUi.cmbSelectionMode->currentIndex(); delete dlgBrushExportOptions; } } else { qApp->processEvents(); // For vector layers to be updated } // the image must be locked at the higher levels KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked()); QRect rc = input->image()->bounds(); brush->setName(exportOptions.name); brush->setSpacing(exportOptions.spacing); brush->setUseColorAsMask(exportOptions.mask); int w = input->image()->width(); int h = input->image()->height(); KisImagePipeBrush *pipeBrush = dynamic_cast(brush); if (pipeBrush) { // Create parasite. XXX: share with KisCustomBrushWidget QVector< QVector > devices; devices.push_back(QVector()); KoProperties properties; properties.setProperty("visible", true); QList layers = input->image()->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (exportOptions.selectionMode) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } KisPipeBrushParasite parasite; // XXX: share code with KisImagePipeBrush, when we figure out how to support more gih features parasite.dim = devices.count(); // XXX Change for multidim! : parasite.ncells = devices.at(0).count(); parasite.rank[0] = parasite.ncells; // ### This can mask some bugs, be careful here in the future parasite.selection[0] = modes.at(0); // XXX needsmovement! parasite.setBrushesCount(); pipeBrush->setParasite(parasite); pipeBrush->setDevices(devices, w, h); } else { QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); brush->setImage(image); } brush->setWidth(w); brush->setHeight(h); QFile f(filename); f.open(QIODevice::WriteOnly); brush->saveToDevice(&f); f.close(); return KisImportExportFilter::OK; } #include "kis_brush_export.moc" diff --git a/plugins/impex/brush/kis_brush_import.cpp b/plugins/impex/brush/kis_brush_import.cpp index 6c0abc4382..4c3982853a 100644 --- a/plugins/impex/brush/kis_brush_import.cpp +++ b/plugins/impex/brush/kis_brush_import.cpp @@ -1,151 +1,151 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * 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_brush_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisBrushImportFactory, "krita_brush_import.json", registerPlugin();) KisBrushImport::KisBrushImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBrushImport::~KisBrushImport() { } KisImportExportFilter::ConversionStatus KisBrushImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration) { Q_UNUSED(configuration); if (to != "application/x-krita") return KisImportExportFilter::BadMimeType; QString filename = inputFile(); if (!filename.isEmpty()) { if (!QFile(filename).exists()) { return KisImportExportFilter::FileNotFound; } KisBrush *brush; if (from == "image/x-gimp-brush") { - brush = new KisGbrBrush(filename); + brush = new KisGimpBrush(filename); } else if (from == "image/x-gimp-brush-animated") { brush = new KisImagePipeBrush(filename); } else { return KisImportExportFilter::BadMimeType; } if (!brush->load()) { delete brush; return KisImportExportFilter::InvalidFormat; } if (!brush->valid()) { delete brush; return KisImportExportFilter::InvalidFormat; } KisDocument * doc = outputDocument(); if (!doc) { delete brush; return KisImportExportFilter::NoDocumentCreated; } doc->prepareForImport(); const KoColorSpace *colorSpace = 0; if (brush->hasColor()) { colorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisImageWSP image = new KisImage(doc->createUndoStore(), brush->width(), brush->height(), colorSpace, brush->name()); image->setProperty("brushspacing", brush->spacing()); KisImagePipeBrush *pipeBrush = dynamic_cast(brush); if (pipeBrush) { - QVector brushes = pipeBrush->brushes(); + QVector brushes = pipeBrush->brushes(); for(int i = brushes.size(); i > 0; i--) { - KisGbrBrush *subbrush = brushes.at(i - 1); + KisGimpBrush *subbrush = brushes.at(i - 1); const KoColorSpace *subColorSpace = 0; if (brush->hasColor()) { subColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { subColorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, subColorSpace); layer->paintDevice()->convertFromQImage(subbrush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer()); } KisAnnotationSP ann = new KisAnimatedBrushAnnotation(pipeBrush->parasite()); image->addAnnotation(ann); } else { KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, colorSpace); layer->paintDevice()->convertFromQImage(brush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer(), 0); } doc->setCurrentImage(image); delete brush; return KisImportExportFilter::OK; } return KisImportExportFilter::StorageCreationError; } #include "kis_brush_import.moc" diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.cpp b/plugins/paintops/libpaintop/kis_brush_chooser.cpp index aa7e24c4bd..7b5d7e3734 100644 --- a/plugins/paintops/libpaintop/kis_brush_chooser.cpp +++ b/plugins/paintops/libpaintop/kis_brush_chooser.cpp @@ -1,363 +1,363 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2009 Sven Langkamp * Copyright (c) 2010 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Srikanth Tiyyagura * * 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_brush_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_brush_registry.h" #include "kis_brush_server.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_multipliers_double_slider_spinbox.h" #include "kis_spacing_selection_widget.h" #include "kis_signals_blocker.h" #include "kis_custom_brush_widget.h" #include "kis_clipboard_brush_widget.h" #include "kis_global.h" -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_debug.h" #include "kis_image.h" /// The resource item delegate for rendering the resource preview class KisBrushDelegate : public QAbstractItemDelegate { public: KisBrushDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} virtual ~KisBrushDelegate() {} /// reimplemented virtual void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const { return option.decorationSize; } }; void KisBrushDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; KisBrush *brush = static_cast(index.internalPointer()); QRect itemRect = option.rect; QImage thumbnail = brush->image(); if (thumbnail.height() > itemRect.height() || thumbnail.width() > itemRect.width()) { thumbnail = thumbnail.scaled(itemRect.size() , Qt::KeepAspectRatio, Qt::SmoothTransformation); } painter->save(); int dx = (itemRect.width() - thumbnail.width()) / 2; int dy = (itemRect.height() - thumbnail.height()) / 2; painter->drawImage(itemRect.x() + dx, itemRect.y() + dy, thumbnail); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->drawRect(option.rect); painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(0.65); painter->fillRect(option.rect, option.palette.highlight()); } painter->restore(); } KisBrushChooser::KisBrushChooser(QWidget *parent, const char *name) : QWidget(parent), m_stampBrushWidget(0), m_clipboardBrushWidget(0) { setObjectName(name); m_lbSize = new QLabel(i18n("Size:"), this); m_slSize = new KisDoubleSliderSpinBox(this); m_slSize->setRange(0, 1000, 2); m_slSize->setValue(5); m_slSize->setExponentRatio(3.0); m_slSize->setSuffix(i18n(" px")); m_slSize->setExponentRatio(3.0); QObject::connect(m_slSize, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemSize(qreal))); m_lbRotation = new QLabel(i18n("Rotation:"), this); m_slRotation = new KisDoubleSliderSpinBox(this); m_slRotation->setRange(0, 360, 0); m_slRotation->setValue(0); m_slRotation->setSuffix(QChar(Qt::Key_degree)); QObject::connect(m_slRotation, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemRotation(qreal))); m_lbSpacing = new QLabel(i18n("Spacing:"), this); m_slSpacing = new KisSpacingSelectionWidget(this); m_slSpacing->setSpacing(true, 1.0); connect(m_slSpacing, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); m_chkColorMask = new QCheckBox(i18n("Use color as mask"), this); QObject::connect(m_chkColorMask, SIGNAL(toggled(bool)), this, SLOT(slotSetItemUseColorAsMask(bool))); m_lbName = new QLabel(this); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); QSharedPointer adapter(new KisBrushResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->showTaggingBar(true); m_itemChooser->setColumnCount(10); m_itemChooser->setRowHeight(30); m_itemChooser->setItemDelegate(new KisBrushDelegate(this)); m_itemChooser->setCurrentItem(0, 0); m_itemChooser->setSynced(true); connect(m_itemChooser, SIGNAL(resourceSelected(KoResource *)), this, SLOT(update(KoResource *))); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setObjectName("main layout"); mainLayout->addWidget(m_lbName); mainLayout->addWidget(m_itemChooser, 10); QPushButton *stampButton = new QPushButton(KisIconUtils::loadIcon("list-add"), i18n("Stamp"), this); QPushButton *clipboardButton = new QPushButton(KisIconUtils::loadIcon("edit-paste"), i18n("Clipboard"), this); stampButton->setToolTip(i18n("Creates a brush tip from the current image selection." "\n If no selection is present the whole image will be used.")); clipboardButton->setToolTip(i18n("Creates a brush tip from the image in the clipboard.")); m_itemChooser->addCustomButton(stampButton, 2); m_itemChooser->addCustomButton(clipboardButton, 3); connect(stampButton, SIGNAL(clicked()), this, SLOT(slotOpenStampBrush())); connect(clipboardButton, SIGNAL(clicked()), SLOT(slotOpenClipboardBrush())); QGridLayout *spacingLayout = new QGridLayout(); spacingLayout->setObjectName("spacing grid layout"); mainLayout->addLayout(spacingLayout, 1); spacingLayout->addWidget(m_lbSize, 1, 0); spacingLayout->addWidget(m_slSize, 1, 1); spacingLayout->addWidget(m_lbRotation, 2, 0); spacingLayout->addWidget(m_slRotation, 2, 1); spacingLayout->addWidget(m_lbSpacing, 3, 0); spacingLayout->addWidget(m_slSpacing, 3, 1); spacingLayout->setColumnStretch(1, 3); QPushButton *resetBrushButton = new QPushButton(i18n("Reset Predefined Tip"), this); resetBrushButton->setToolTip(i18n("Reloads Spacing from file\nSets Scale to 1.0\nSets Rotation to 0.0")); connect(resetBrushButton, SIGNAL(clicked()), SLOT(slotResetBrush())); QHBoxLayout *resetHLayout = new QHBoxLayout(); resetHLayout->addWidget(m_chkColorMask, 0); resetHLayout->addWidget(resetBrushButton, 0, Qt::AlignRight); spacingLayout->addLayout(resetHLayout, 4, 0, 1, 2); update(m_itemChooser->currentResource()); } KisBrushChooser::~KisBrushChooser() { } void KisBrushChooser::setBrush(KisBrushSP _brush) { m_itemChooser->setCurrentResource(_brush.data()); update(_brush.data()); } void KisBrushChooser::slotResetBrush() { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->load(); brush->setScale(1.0); brush->setAngle(0.0); slotActivatedBrush(brush); update(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemSize(qreal sizeValue) { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { int brushWidth = brush->width(); brush->setScale(sizeValue / qreal(brushWidth)); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemRotation(qreal rotationValue) { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setAngle(rotationValue / 180.0 * M_PI); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSpacingChanged() { KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setSpacing(m_slSpacing->spacing()); brush->setAutoSpacing(m_slSpacing->autoSpacingActive(), m_slSpacing->autoSpacingCoeff()); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask) { - KisGbrBrush *brush = dynamic_cast(m_itemChooser->currentResource()); + KisGimpBrush *brush = dynamic_cast(m_itemChooser->currentResource()); if (brush) { brush->setUseColorAsMask(useColorAsMask); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotOpenStampBrush() { if(!m_stampBrushWidget) { m_stampBrushWidget = new KisCustomBrushWidget(this, i18n("Stamp"), m_image); m_stampBrushWidget->setModal(false); connect(m_stampBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource *)), SLOT(slotNewPredefinedBrush(KoResource *))); } QDialog::DialogCode result = (QDialog::DialogCode)m_stampBrushWidget->exec(); if(result) { update(m_itemChooser->currentResource()); } } void KisBrushChooser::slotOpenClipboardBrush() { if(!m_clipboardBrushWidget) { m_clipboardBrushWidget = new KisClipboardBrushWidget(this, i18n("Clipboard"), m_image); m_clipboardBrushWidget->setModal(true); connect(m_clipboardBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource *)), SLOT(slotNewPredefinedBrush(KoResource *))); } QDialog::DialogCode result = (QDialog::DialogCode)m_clipboardBrushWidget->exec(); if(result) { update(m_itemChooser->currentResource()); } } void KisBrushChooser::update(KoResource * resource) { KisBrush* brush = dynamic_cast(resource); if (brush) { QString text = QString("%1 (%2 x %3)") .arg(i18n(brush->name().toUtf8().data())) .arg(brush->width()) .arg(brush->height()); m_lbName->setText(text); m_slSpacing->setSpacing(brush->autoSpacingActive(), brush->autoSpacingActive() ? brush->autoSpacingCoeff() : brush->spacing()); m_slRotation->setValue(brush->angle() * 180 / M_PI); m_slSize->setValue(brush->width() * brush->scale()); // useColorAsMask support is only in gimp brush so far - KisGbrBrush *gimpBrush = dynamic_cast(resource); + KisGimpBrush *gimpBrush = dynamic_cast(resource); if (gimpBrush) { m_chkColorMask->setChecked(gimpBrush->useColorAsMask()); } m_chkColorMask->setEnabled(brush->hasColor() && gimpBrush); slotActivatedBrush(brush); emit sigBrushChanged(); } } void KisBrushChooser::slotActivatedBrush(KoResource * resource) { KisBrush* brush = dynamic_cast(resource); if (m_brush != brush) { if (m_brush) { m_brush->clearBrushPyramid(); } m_brush = brush; if (m_brush) { m_brush->prepareBrushPyramid(); } } } void KisBrushChooser::slotNewPredefinedBrush(KoResource *resource) { m_itemChooser->setCurrentResource(resource); update(resource); } void KisBrushChooser::setBrushSize(qreal xPixels, qreal yPixels) { Q_UNUSED(yPixels); qreal oldWidth = m_brush->width() * m_brush->scale(); qreal newWidth = oldWidth + xPixels; newWidth = qMax(newWidth, qreal(0.1)); m_slSize->setValue(newWidth); } void KisBrushChooser::setImage(KisImageWSP image) { m_image = image; } #include "moc_kis_brush_chooser.cpp" diff --git a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp index e2346f550c..6bd7fa528f 100644 --- a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp @@ -1,159 +1,159 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2013 Somsubhra Bairi * * 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_clipboard_brush_widget.h" #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_clipboard.h" #include "kis_paint_device.h" -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_brush_server.h" KisClipboardBrushWidget::KisClipboardBrushWidget(QWidget *parent, const QString &caption, KisImageWSP image) : KisWdgClipboardBrush(parent), m_image(image) { setWindowTitle(caption); preview->setScaledContents(true); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; m_clipboard = KisClipboard::instance(); connect(m_clipboard, SIGNAL(clipChanged()), this, SLOT(slotCreateBrush())); connect(colorAsmask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAddPredefined())); spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisClipboardBrushWidget::~KisClipboardBrushWidget() { } void KisClipboardBrushWidget::slotCreateBrush() { // do nothing if it's hidden otherwise it can break the active brush is something is copied if (m_clipboard->hasClip() && !isHidden()) { pd = m_clipboard->clip(QRect(0, 0, 0, 0), false); //Weird! Don't know how this works! if (pd) { QRect rc = pd->exactBounds(); - m_brush = new KisGbrBrush(pd, rc.x(), rc.y(), rc.width(), rc.height()); + m_brush = new KisGimpBrush(pd, rc.x(), rc.y(), rc.width(), rc.height()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_CLIPBOARD_BRUSH_FILENAME); m_brush->setName(TEMPORARY_CLIPBOARD_BRUSH_NAME); m_brush->setValid(true); preview->setPixmap(QPixmap::fromImage(m_brush->image())); } } else { preview->setText(i18n("Nothing copied\n to Clipboard")); } if(m_brush == 0) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } else { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } } void KisClipboardBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisClipboardBrushWidget::showEvent(QShowEvent *) { slotCreateBrush(); } void KisClipboardBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { - static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); + static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } void KisClipboardBrushWidget::slotAddPredefined() { if(!m_brush) return; QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension = ".gbr"; QString name = nameEdit->text(); QString tempFileName; QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); if (m_rServerAdapter) { - KisGbrBrush *resource = dynamic_cast(m_brush->clone()); + KisGimpBrush *resource = dynamic_cast(m_brush->clone()); resource->setFilename(tempFileName); if (nameEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsmask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } #include "moc_kis_clipboard_brush_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp index 65ead643ee..feec96ee89 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp @@ -1,251 +1,251 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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_custom_brush_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" -#include "kis_gbr_brush.h" +#include "kis_gimp_brush.h" #include "kis_imagepipe_brush.h" #include #include "kis_brush_server.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include #include #include "kis_iterator_ng.h" KisCustomBrushWidget::KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image) : KisWdgCustomBrush(parent) , m_image(image) { setWindowTitle(caption); preview->setScaledContents(true); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; connect(this, SIGNAL(accepted()), SLOT(slotAddPredefined())); connect(brushStyle, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrentBrush(int))); connect(colorAsMask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisCustomBrushWidget::~KisCustomBrushWidget() { } KisBrushSP KisCustomBrushWidget::brush() { return m_brush; } void KisCustomBrushWidget::showEvent(QShowEvent *) { slotUpdateCurrentBrush(0); } void KisCustomBrushWidget::slotUpdateCurrentBrush(int) { if (brushStyle->currentIndex() == 0) { comboBox2->setEnabled(false); } else { comboBox2->setEnabled(true); } if (m_image) { createBrush(); if (m_brush) { preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } } void KisCustomBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisCustomBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { - static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); + static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } void KisCustomBrushWidget::slotAddPredefined() { QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension; if (brushStyle->currentIndex() == 0) { extension = ".gbr"; } else { extension = ".gih"; } QString name = nameLineEdit->text(); QString tempFileName; { QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); } // Add it to the brush server, so that it automatically gets to the mediators, and // so to the other brush choosers can pick it up, if they want to if (m_rServerAdapter && m_brush) { qDebug() << "m_brush" << m_brush; - KisGbrBrush *resource = dynamic_cast(m_brush->clone()); + KisGimpBrush *resource = dynamic_cast(m_brush->clone()); resource->setFilename(tempFileName); if (nameLineEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsMask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } void KisCustomBrushWidget::createBrush() { if (!m_image) return; if (brushStyle->currentIndex() == 0) { KisSelectionSP selection = m_image->globalSelection(); // create copy of the data m_image->lock(); KisPaintDeviceSP dev = new KisPaintDevice(*m_image->projection()); m_image->unlock(); if (!selection) { - m_brush = new KisGbrBrush(dev, 0, 0, m_image->width(), m_image->height()); + m_brush = new KisGimpBrush(dev, 0, 0, m_image->width(), m_image->height()); } else { // apply selection mask QRect r = selection->selectedExactRect(); dev->crop(r); KisHLineIteratorSP pixelIt = dev->createHLineIteratorNG(r.x(), r.top(), r.width()); KisHLineConstIteratorSP maskIt = selection->projection()->createHLineIteratorNG(r.x(), r.top(), r.width()); for (qint32 y = r.top(); y <= r.bottom(); ++y) { do { dev->colorSpace()->applyAlphaU8Mask(pixelIt->rawData(), maskIt->oldRawData(), 1); } while (pixelIt->nextPixel() && maskIt->nextPixel()); pixelIt->nextRow(); maskIt->nextRow(); } QRect rc = dev->exactBounds(); - m_brush = new KisGbrBrush(dev, rc.x(), rc.y(), rc.width(), rc.height()); + m_brush = new KisGimpBrush(dev, rc.x(), rc.y(), rc.width(), rc.height()); } } else { // For each layer in the current image, create a new image, and add it to the list QVector< QVector > devices; devices.push_back(QVector()); int w = m_image->width(); int h = m_image->height(); m_image->lock(); // We only loop over the rootLayer. Since we actually should have a layer selection // list, no need to elaborate on that here and now KoProperties properties; properties.setProperty("visible", true); QList layers = m_image->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (comboBox2->currentIndex()) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } m_brush = new KisImagePipeBrush(m_image->objectName(), w, h, devices, modes); m_image->unlock(); } - static_cast(m_brush.data())->setUseColorAsMask(colorAsMask->isChecked()); + static_cast(m_brush.data())->setUseColorAsMask(colorAsMask->isChecked()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_FILENAME); m_brush->setName(TEMPORARY_BRUSH_NAME); m_brush->setValid(true); }