File indexing completed on 2024-12-22 04:15:37

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_brush_export.h"
0008 
0009 #include <QCheckBox>
0010 #include <QSlider>
0011 #include <QBuffer>
0012 
0013 #include <KoProperties.h>
0014 #include <KoDialog.h>
0015 #include <kpluginfactory.h>
0016 #include <QFileInfo>
0017 
0018 #include <KisExportCheckRegistry.h>
0019 #include <kis_paint_device.h>
0020 #include <KisViewManager.h>
0021 #include <kis_image.h>
0022 #include <KisDocument.h>
0023 #include <kis_paint_layer.h>
0024 #include <kis_spacing_selection_widget.h>
0025 #include <kis_gbr_brush.h>
0026 #include <kis_imagepipe_brush.h>
0027 #include <kis_pipebrush_parasite.h>
0028 #include <KisAnimatedBrushAnnotation.h>
0029 #include <KisWdgOptionsBrush.h>
0030 #include <KisImportExportManager.h>
0031 #include <kis_config.h>
0032 
0033 struct KisBrushExportOptions {
0034     qreal spacing;
0035     bool mask;
0036     int brushStyle;
0037     int dimensions;
0038     qint32 ranks[KisPipeBrushParasite::MaxDim];
0039     qint32 selectionModes[KisPipeBrushParasite::MaxDim];
0040     QString name;
0041 };
0042 
0043 
0044 K_PLUGIN_FACTORY_WITH_JSON(KisBrushExportFactory, "krita_brush_export.json", registerPlugin<KisBrushExport>();)
0045 
0046 KisBrushExport::KisBrushExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
0047 {
0048 }
0049 
0050 KisBrushExport::~KisBrushExport()
0051 {
0052 }
0053 
0054 KisImportExportErrorCode KisBrushExport::convert(KisDocument *document, QIODevice *io,  KisPropertiesConfigurationSP configuration)
0055 {
0056 
0057 // XXX: Loading the parasite itself was commented out -- needs investigation
0058 //    KisAnnotationSP annotation = document->savingImage()->annotation("ImagePipe Parasite");
0059 //    KisPipeBrushParasite parasite;
0060 //    if (annotation) {
0061 //        QBuffer buf(const_cast<QByteArray*>(&annotation->annotation()));
0062 //        buf.open(QBuffer::ReadOnly);
0063 //        parasite.loadFromDevice(&buf);
0064 //        buf.close();
0065 //    }
0066 
0067     KisBrushExportOptions exportOptions;
0068 
0069     if (document->savingImage()->dynamicPropertyNames().contains("brushspacing")) {
0070         exportOptions.spacing = document->savingImage()->property("brushspacing").toFloat();
0071     }
0072     else {
0073         exportOptions.spacing = configuration->getInt("spacing");
0074     }
0075     if (!configuration->getString("name").isEmpty()) {
0076         exportOptions.name = configuration->getString("name");
0077     }
0078     else {
0079         exportOptions.name = document->savingImage()->objectName();
0080     }
0081 
0082     exportOptions.mask = configuration->getBool("mask");
0083     exportOptions.brushStyle = configuration->getInt("brushStyle");
0084     exportOptions.dimensions = configuration->getInt("dimensions");
0085 
0086     for (int i = 0; i < KisPipeBrushParasite::MaxDim; ++i) {
0087         exportOptions.selectionModes[i] = configuration->getInt("selectionMode" + QString::number(i));
0088         exportOptions.ranks[i] = configuration->getInt("rank" + QString::number(i));
0089     }
0090 
0091     KisGbrBrush *brush = 0;
0092     if (mimeType() == "image/x-gimp-brush") {
0093         brush = new KisGbrBrush(filename());
0094     }
0095     else if (mimeType() == "image/x-gimp-brush-animated") {
0096         brush = new KisImagePipeBrush(filename());
0097     }
0098     else {
0099         return ImportExportCodes::FileFormatIncorrect;
0100     }
0101 
0102     qApp->processEvents(); // For vector layers to be updated
0103 
0104     QRect rc = document->savingImage()->bounds();
0105 
0106     brush->setSpacing(exportOptions.spacing);
0107 
0108     KisImagePipeBrush *pipeBrush = dynamic_cast<KisImagePipeBrush*>(brush);
0109     if (pipeBrush) {
0110         // Create parasite. XXX: share with KisCustomBrushWidget
0111         QVector< QVector<KisPaintDevice*> > devices;
0112         devices.push_back(QVector<KisPaintDevice*>());
0113 
0114         KoProperties properties;
0115         properties.setProperty("visible", true);
0116         QList<KisNodeSP> layers = document->savingImage()->root()->childNodes(QStringList("KisLayer"), properties);
0117 
0118         Q_FOREACH (KisNodeSP node, layers) {
0119             // push_front to behave exactly as gimp for gih creation
0120             devices[0].push_front(node->projection().data());
0121         }
0122 
0123         QVector<KisParasite::SelectionMode > modes;
0124 
0125         for (int i = 0; i < KisPipeBrushParasite::MaxDim; ++i) {
0126             switch (exportOptions.selectionModes[i]) {
0127             case 0: modes.push_back(KisParasite::Constant); break;
0128             case 1: modes.push_back(KisParasite::Random); break;
0129             case 2: modes.push_back(KisParasite::Incremental); break;
0130             case 3: modes.push_back(KisParasite::Pressure); break;
0131             case 4: modes.push_back(KisParasite::Angular); break;
0132             case 5: modes.push_back(KisParasite::Velocity); break;
0133             default: modes.push_back(KisParasite::Incremental);
0134             }
0135         }
0136 
0137         KisPipeBrushParasite parasite;
0138 
0139         parasite.dim = exportOptions.dimensions;
0140         parasite.ncells = devices.at(0).count();
0141 
0142         int maxRanks = 0;
0143         for (int i = 0; i < KisPipeBrushParasite::MaxDim; ++i) {
0144             // ### This can mask some bugs, be careful here in the future
0145             parasite.rank[i] = exportOptions.ranks[i];
0146             parasite.selection[i] = modes.at(i);
0147             maxRanks += exportOptions.ranks[i];
0148         }
0149 
0150         if (maxRanks > layers.count()) {
0151             return ImportExportCodes::FileFormatIncorrect;
0152         }
0153         // XXX needs movement!
0154         parasite.setBrushesCount();
0155         pipeBrush->setParasite(parasite);
0156         pipeBrush->setDevices(devices, rc.width(), rc.height());
0157     }
0158     else {
0159         if (exportOptions.mask) {
0160             QImage image = document->savingImage()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0161             brush->setImage(image);
0162             brush->setBrushTipImage(image);
0163         } else {
0164             brush->initFromPaintDev(document->savingImage()->projection(),0,0,rc.width(), rc.height());
0165         }
0166     }
0167 
0168     brush->setName(exportOptions.name);
0169     // brushes are created after devices are loaded, call mask mode after that
0170     brush->setBrushApplication(exportOptions.mask ? ALPHAMASK : IMAGESTAMP);
0171     brush->setWidth(rc.width());
0172     brush->setHeight(rc.height());
0173 
0174     if (brush->saveToDevice(io)) {
0175         return ImportExportCodes::OK;
0176     }
0177     else {
0178         return ImportExportCodes::Failure;
0179     }
0180 }
0181 
0182 KisPropertiesConfigurationSP KisBrushExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const
0183 {
0184     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0185     cfg->setProperty("spacing", 1.0);
0186     cfg->setProperty("name", "");
0187     cfg->setProperty("mask", true);
0188     cfg->setProperty("brushStyle", 0);
0189     cfg->setProperty("dimensions", 1);
0190 
0191     for (int i = 0; i < KisPipeBrushParasite::MaxDim; ++i) {
0192         cfg->setProperty("selectionMode" + QString::number(i), 2);
0193         cfg->getInt("rank" + QString::number(i), 0);
0194     }
0195     return cfg;
0196 }
0197 
0198 KisConfigWidget *KisBrushExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &to) const
0199 {
0200     KisWdgOptionsBrush *wdg = new KisWdgOptionsBrush(parent);
0201     if (to == "image/x-gimp-brush") {
0202         wdg->groupBox->setVisible(false);
0203         wdg->animStyleGroup->setVisible(false);
0204     }
0205     else if (to == "image/x-gimp-brush-animated") {
0206         wdg->groupBox->setVisible(true);
0207         wdg->animStyleGroup->setVisible(true);
0208     }
0209 
0210     // preload gih name with chosen filename
0211     QFileInfo fileLocation(filename());
0212     wdg->nameLineEdit->setText(fileLocation.completeBaseName());
0213     return wdg;
0214 }
0215 
0216 void KisBrushExport::initializeCapabilities()
0217 {
0218     QList<QPair<KoID, KoID> > supportedColorModels;
0219     supportedColorModels << QPair<KoID, KoID>()
0220             << QPair<KoID, KoID>(RGBAColorModelID, Integer8BitsColorDepthID)
0221             << QPair<KoID, KoID>(GrayAColorModelID, Integer8BitsColorDepthID);
0222     addSupportedColorModels(supportedColorModels, "Gimp Brushes");
0223     if (mimeType() == "image/x-gimp-brush-animated") {
0224         addCapability(KisExportCheckRegistry::instance()->get("MultiLayerCheck")->create(KisExportCheckBase::SUPPORTED));
0225         addCapability(KisExportCheckRegistry::instance()->get("LayerOpacityCheck")->create(KisExportCheckBase::SUPPORTED));
0226     }
0227 }
0228 
0229 
0230 #include "kis_brush_export.moc"
0231