diff --git a/libs/flake/svg/SvgWriter.cpp b/libs/flake/svg/SvgWriter.cpp index ed7932bc40..0e5b8ab529 100644 --- a/libs/flake/svg/SvgWriter.cpp +++ b/libs/flake/svg/SvgWriter.cpp @@ -1,285 +1,298 @@ /* This file is part of the KDE project Copyright (C) 2002 Lars Siebold Copyright (C) 2002-2003,2005 Rob Buis Copyright (C) 2002,2005-2006 David Faure Copyright (C) 2002 Werner Trobin Copyright (C) 2002 Lennart Kudling Copyright (C) 2004 Nicolas Goutte Copyright (C) 2005 Boudewijn Rempt Copyright (C) 2005 Raphael Langerhorst Copyright (C) 2005 Thomas Zander Copyright (C) 2005,2007-2008 Jan Hambrecht Copyright (C) 2006 Inge Wallin Copyright (C) 2006 Martin Pfeiffer Copyright (C) 2006 Gábor Lehel Copyright (C) 2006 Laurent Montel Copyright (C) 2006 Christian Mueller Copyright (C) 2006 Ariya Hidayat Copyright (C) 2010 Thorsten Zachmann This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SvgWriter.h" #include "SvgUtil.h" #include "SvgSavingContext.h" #include "SvgShape.h" #include "SvgStyleWriter.h" #include #include #include #include #include #include #include #include #include #include #include #include SvgWriter::SvgWriter(const QList &layers) : m_writeInlineImages(true) { Q_FOREACH (KoShapeLayer *layer, layers) m_toplevelShapes.append(layer); } SvgWriter::SvgWriter(const QList &toplevelShapes) : m_toplevelShapes(toplevelShapes) , m_writeInlineImages(true) { } SvgWriter::~SvgWriter() { } bool SvgWriter::save(const QString &filename, const QSizeF &pageSize, bool writeInlineImages) { QFile fileOut(filename); if (!fileOut.open(QIODevice::WriteOnly)) return false; m_writeInlineImages = writeInlineImages; const bool success = save(fileOut, pageSize); m_writeInlineImages = true; fileOut.close(); return success; } bool SvgWriter::save(QIODevice &outputDevice, const QSizeF &pageSize) { if (m_toplevelShapes.isEmpty()) { return false; } QTextStream svgStream(&outputDevice); svgStream.setCodec("UTF-8"); // standard header: svgStream << "" << endl; svgStream << "" << endl; // add some PR. one line is more than enough. svgStream << "" << endl; svgStream << "" << endl; { SvgSavingContext savingContext(outputDevice, m_writeInlineImages); saveShapes(m_toplevelShapes, savingContext); } // end tag: svgStream << endl << "" << endl; return true; } bool SvgWriter::saveDetached(QIODevice &outputDevice) { if (m_toplevelShapes.isEmpty()) return false; SvgSavingContext savingContext(outputDevice, m_writeInlineImages); saveShapes(m_toplevelShapes, savingContext); return true; } bool SvgWriter::saveDetached(SvgSavingContext &savingContext) { if (m_toplevelShapes.isEmpty()) return false; saveShapes(m_toplevelShapes, savingContext); return true; } void SvgWriter::saveShapes(const QList shapes, SvgSavingContext &savingContext) { // top level shapes Q_FOREACH (KoShape *shape, shapes) { KoShapeLayer *layer = dynamic_cast(shape); if(layer) { saveLayer(layer, savingContext); } else { KoShapeGroup *group = dynamic_cast(shape); if (group) saveGroup(group, savingContext); else saveShape(shape, savingContext); } } } void SvgWriter::saveLayer(KoShapeLayer *layer, SvgSavingContext &context) { context.shapeWriter().startElement("g"); context.shapeWriter().addAttribute("id", context.getID(layer)); QList sortedShapes = layer->shapes(); std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex); Q_FOREACH (KoShape * shape, sortedShapes) { KoShapeGroup * group = dynamic_cast(shape); if (group) saveGroup(group, context); else saveShape(shape, context); } context.shapeWriter().endElement(); } void SvgWriter::saveGroup(KoShapeGroup * group, SvgSavingContext &context) { context.shapeWriter().startElement("g"); context.shapeWriter().addAttribute("id", context.getID(group)); SvgUtil::writeTransformAttributeLazy("transform", group->transformation(), context.shapeWriter()); SvgStyleWriter::saveSvgStyle(group, context); QList sortedShapes = group->shapes(); std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex); Q_FOREACH (KoShape * shape, sortedShapes) { KoShapeGroup * childGroup = dynamic_cast(shape); if (childGroup) saveGroup(childGroup, context); else saveShape(shape, context); } context.shapeWriter().endElement(); } void SvgWriter::saveShape(KoShape *shape, SvgSavingContext &context) { SvgShape *svgShape = dynamic_cast(shape); if (svgShape && svgShape->saveSvg(context)) return; KoPathShape * path = dynamic_cast(shape); if (path) { savePath(path, context); } else { // generic saving of shape via a switch element saveGeneric(shape, context); } } void SvgWriter::savePath(KoPathShape *path, SvgSavingContext &context) { context.shapeWriter().startElement("path"); context.shapeWriter().addAttribute("id", context.getID(path)); SvgUtil::writeTransformAttributeLazy("transform", path->transformation(), context.shapeWriter()); SvgStyleWriter::saveSvgStyle(path, context); context.shapeWriter().addAttribute("d", path->toString(context.userSpaceTransform())); context.shapeWriter().endElement(); } void SvgWriter::saveGeneric(KoShape *shape, SvgSavingContext &context) { const QRectF bbox = shape->boundingRect(); // paint shape to the image KoShapePainter painter; painter.setShapes(QList()<< shape); // generate svg from shape QBuffer svgBuffer; QSvgGenerator svgGenerator; svgGenerator.setOutputDevice(&svgBuffer); + /** + * HACK ALERT: Qt (and Krita 3.x) has a weird bug, it assumes that all font sizes are + * defined in 96 ppi resolution, even though your the resolution in QSvgGenerator + * is manually set to 72 ppi. So here we do a tricky thing: we set a fake resolution + * to (72 * 72 / 96) = 54 ppi, which guarantees that the text, when painted in 96 ppi, + * will be actually painted in 72 ppi. + * + * BUG: 389802 + */ + if (shape->shapeId() == "TextShapeID") { + svgGenerator.setResolution(54); + } + QPainter svgPainter; svgPainter.begin(&svgGenerator); painter.paint(svgPainter, SvgUtil::toUserSpace(bbox).toRect(), bbox); svgPainter.end(); // remove anything before the start of the svg element from the buffer int startOfContent = svgBuffer.buffer().indexOf("0) { svgBuffer.buffer().remove(0, startOfContent); } // check if painting to svg produced any output if (svgBuffer.buffer().isEmpty()) { // prepare a transparent image, make it twice as big as the original size QImage image(2*bbox.size().toSize(), QImage::Format_ARGB32); image.fill(0); painter.paint(image); context.shapeWriter().startElement("image"); context.shapeWriter().addAttribute("id", context.getID(shape)); context.shapeWriter().addAttributePt("x", bbox.x()); context.shapeWriter().addAttributePt("y", bbox.y()); context.shapeWriter().addAttributePt("width", bbox.width()); context.shapeWriter().addAttributePt("height", bbox.height()); context.shapeWriter().addAttribute("xlink:href", context.saveImage(image)); context.shapeWriter().endElement(); // image } else { context.shapeWriter().addCompleteElement(&svgBuffer); } // TODO: once we support saving single (flat) odf files // we can embed these here to have full support for generic shapes }