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