File indexing completed on 2025-07-06 10:21:33
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2002-2005, 2007 Rob Buis <buis@kde.org> 0003 * SPDX-FileCopyrightText: 2002-2004 Nicolas Goutte <nicolasg@snafu.de> 0004 * SPDX-FileCopyrightText: 2005-2006 Tim Beaulen <tbscope@gmail.com> 0005 * SPDX-FileCopyrightText: 2005-2009 Jan Hambrecht <jaham@gmx.net> 0006 * SPDX-FileCopyrightText: 2005, 2007 Thomas Zander <zander@kde.org> 0007 * SPDX-FileCopyrightText: 2006-2007 Inge Wallin <inge@lysator.liu.se> 0008 * SPDX-FileCopyrightText: 2007-2008 Thorsten Zachmann <t.zachmann@zagge.de> 0009 0010 * SPDX-License-Identifier: LGPL-2.0-or-later 0011 */ 0012 0013 #include "SvgImport.h" 0014 #include "SvgParser.h" 0015 0016 #include <KarbonPart.h> 0017 #include <KarbonDocument.h> 0018 0019 #include <KoShape.h> 0020 #include <KoShapeLayer.h> 0021 #include <KoShapeGroup.h> 0022 #include <KoFilterChain.h> 0023 #include <commands/KoShapeUngroupCommand.h> 0024 #include <KoXmlReader.h> 0025 #include <KoPAPage.h> 0026 #include <KoPAMasterPage.h> 0027 #include <KoPageLayout.h> 0028 0029 #include <kpluginfactory.h> 0030 #include <KCompressionDevice> 0031 0032 #include <QFileInfo> 0033 #include <QDebug> 0034 #include <QLoggingCategory> 0035 0036 K_PLUGIN_FACTORY_WITH_JSON(SvgImportFactory, "calligra_filter_svg2karbon.json", 0037 registerPlugin<SvgImport>();) 0038 0039 const QLoggingCategory &SVG_LOG() 0040 { 0041 static const QLoggingCategory category("calligra.filter.svg2karbon"); 0042 return category; 0043 } 0044 0045 #define debugSvg qCDebug(SVG_LOG) 0046 #define warnSvg qCWarning(SVG_LOG) 0047 #define errorSvg qCCritical(SVG_LOG) 0048 0049 0050 SvgImport::SvgImport(QObject*parent, const QVariantList&) 0051 : KoFilter(parent), m_document(0) 0052 { 0053 } 0054 0055 SvgImport::~SvgImport() 0056 { 0057 } 0058 0059 KoFilter::ConversionStatus SvgImport::convert(const QByteArray& from, const QByteArray& to) 0060 { 0061 // check for proper conversion 0062 if (to != "application/vnd.oasis.opendocument.graphics") 0063 return KoFilter::NotImplemented; 0064 if (from != "image/svg+xml" && from != "image/svg+xml-compressed") 0065 return KoFilter::NotImplemented; 0066 0067 //Find the last extension 0068 QString strExt; 0069 QString fileIn(m_chain->inputFile()); 0070 const int result = fileIn.lastIndexOf('.'); 0071 if (result >= 0) 0072 strExt = fileIn.mid(result).toLower(); 0073 0074 const KCompressionDevice::CompressionType compressionType = 0075 (strExt == QLatin1String(".gz")) //in case of .svg.gz (logical extension) 0076 || (strExt == QLatin1String(".svgz")) ? //in case of .svgz (extension used prioritary) 0077 KCompressionDevice::GZip : 0078 (strExt == QLatin1String(".bz2")) ? //in case of .svg.bz2 (logical extension) 0079 KCompressionDevice::BZip2 : 0080 KCompressionDevice::None; 0081 0082 /*debugSvg <<"File extension: -" << strExt <<"- Compression:" << strMime;*/ 0083 0084 QIODevice* in = new KCompressionDevice(fileIn, compressionType); 0085 if (!in->open(QIODevice::ReadOnly)) { 0086 errorSvg << "Cannot open file! Aborting!" << endl; 0087 delete in; 0088 return KoFilter::FileNotFound; 0089 } 0090 0091 int line, col; 0092 QString errormessage; 0093 0094 KoXmlDocument inputDoc; 0095 0096 const bool parsed = inputDoc.setContent(in, &errormessage, &line, &col); 0097 0098 in->close(); 0099 delete in; 0100 0101 if (! parsed) { 0102 errorSvg << "Error while parsing file: " 0103 << "at line " << line << " column: " << col 0104 << " message: " << errormessage << endl; 0105 // ### TODO: feedback to the user 0106 return KoFilter::ParsingError; 0107 } 0108 0109 m_document = dynamic_cast<KarbonDocument*>(m_chain->outputDocument()); 0110 if (!m_document) { 0111 return KoFilter::CreationError; 0112 } 0113 if (m_document->pages().isEmpty()) { 0114 KoPAMasterPage *mp = dynamic_cast<KoPAMasterPage*>(m_document->pages(true).value(0)); 0115 if (!mp) { 0116 mp = new KoPAMasterPage(); 0117 m_document->insertPage(mp, 0); 0118 } 0119 m_document->insertPage(new KoPAPage(mp), 0); 0120 } 0121 // Do the conversion! 0122 convert(inputDoc.documentElement()); 0123 0124 return KoFilter::OK; 0125 } 0126 0127 void SvgImport::convert(const KoXmlElement &rootElement) 0128 { 0129 if (! m_document) 0130 return; 0131 0132 // set default page size to A4 0133 QSizeF pageSize(550.0, 841.0); 0134 0135 SvgParser parser(m_document->resourceManager()); 0136 0137 parser.setXmlBaseDir(QFileInfo(m_chain->inputFile()).filePath()); 0138 0139 QList<KoShape*> toplevelShapes = parser.parseSvg(rootElement, &pageSize); 0140 // parse the root svg element 0141 buildDocument(toplevelShapes, parser.shapes()); 0142 0143 // set the page size 0144 KoPageLayout & layout = m_document->pages().at(0)->pageLayout(); 0145 layout.width = pageSize.width(); 0146 layout.height = pageSize.height(); 0147 } 0148 0149 void SvgImport::buildDocument(const QList<KoShape*> &toplevelShapes, const QList<KoShape*> &shapes) 0150 { 0151 Q_UNUSED(shapes); 0152 KoPAPageBase *page = m_document->pages().first(); 0153 // if we have only top level groups, make them layers 0154 bool onlyTopLevelGroups = true; 0155 foreach(KoShape * shape, toplevelShapes) { 0156 if (! dynamic_cast<KoShapeGroup*>(shape) || shape->filterEffectStack()) { 0157 onlyTopLevelGroups = false; 0158 break; 0159 } 0160 } 0161 KoShapeLayer *oldLayer = 0; 0162 if (page->shapeCount()) { 0163 oldLayer = dynamic_cast<KoShapeLayer*>(page->shapes().first()); 0164 } 0165 if (onlyTopLevelGroups) { 0166 foreach(KoShape * shape, toplevelShapes) { 0167 // ungroup toplevel groups 0168 KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape); 0169 QList<KoShape*> children = group->shapes(); 0170 KoShapeUngroupCommand cmd(group, children, QList<KoShape*>() << group); 0171 cmd.redo(); 0172 0173 KoShapeLayer *layer = new KoShapeLayer(); 0174 foreach(KoShape * child, children) { 0175 layer->addShape(child); 0176 } 0177 if (!group->name().isEmpty()) { 0178 layer->setName(group->name()); 0179 } 0180 layer->setVisible(group->isVisible()); 0181 layer->setZIndex(group->zIndex()); 0182 page->addShape(layer); 0183 delete group; 0184 } 0185 } else { 0186 KoShapeLayer *layer = new KoShapeLayer(); 0187 foreach(KoShape * shape, toplevelShapes) { 0188 layer->addShape(shape); 0189 } 0190 page->addShape(layer); 0191 } 0192 if (oldLayer) { 0193 page->removeShape(oldLayer); 0194 delete oldLayer; 0195 } 0196 } 0197 0198 #include "SvgImport.moc"