/* libwpg * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) * Copyright (C) 2005 Fridrich Strba (fridrich.strba@bluewin.ch) * * 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; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02111-1301 USA * * For further information visit http://libwpg.sourceforge.net */ /* "This product is not manufactured, approved, or supported by * Corel Corporation or Corel Corporation Limited." */ #include "WPGSVGGenerator.h" #include #include #include static std::string doubleToString(const double value) { std::ostringstream tempStream; tempStream << value; #ifndef __ANDROID__ std::string decimalPoint(localeconv()->decimal_point); #else std::string decimalPoint("."); #endif if ((decimalPoint.size() == 0) || (decimalPoint == ".")) return tempStream.str(); std::string stringValue(tempStream.str()); if (!stringValue.empty()) { std::string::size_type pos; while ((pos = stringValue.find(decimalPoint)) != std::string::npos) stringValue.replace(pos,decimalPoint.size(),"."); } return stringValue; } libwpg::WPGSVGGenerator::WPGSVGGenerator(std::ostream & output_sink): m_gradient(), m_style(), m_gradientIndex(1), m_shadowIndex(1), m_outputSink(output_sink) { } libwpg::WPGSVGGenerator::~WPGSVGGenerator() { } void libwpg::WPGSVGGenerator::startGraphics(const WPXPropertyList &propList) { m_outputSink << "\n"; m_outputSink << "\n"; m_outputSink << "\n"; m_outputSink << "getDouble())) << "\" "; if (propList["svg:height"]) m_outputSink << "height=\"" << doubleToString(72*(propList["svg:height"]->getDouble())) << "\""; m_outputSink << " >\n"; } void libwpg::WPGSVGGenerator::endGraphics() { m_outputSink << "\n"; } void libwpg::WPGSVGGenerator::setStyle(const ::WPXPropertyList &propList, const ::WPXPropertyListVector& gradient) { m_style.clear(); m_style = propList; m_gradient = gradient; if(propList["draw:shadow"] && propList["draw:shadow"]->getStr() == "visible") { m_outputSink << "\n"; m_outputSink << ""; m_outputSink << "getDouble()) << "\" "; m_outputSink << "dy=\"" << doubleToString(72*propList["draw:shadow-offset-y"]->getDouble()) << "\"/>"; m_outputSink << "getDouble()); m_outputSink << " 0 0 0 0 " << doubleToString(propList["libwpg:shadow-color-g"]->getDouble()); m_outputSink << " 0 0 0 0 " << doubleToString(propList["libwpg:shadow-color-b"]->getDouble()); if(m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1) m_outputSink << " 0 0 0 " << doubleToString(propList["draw:shadow-opacity"]->getDouble()/propList["draw:opacity"]->getDouble()) << " 0\"/>"; else m_outputSink << " 0 0 0 " << doubleToString(propList["draw:shadow-opacity"]->getDouble()) << " 0\"/>"; m_outputSink << ""; } if(propList["draw:fill"] && propList["draw:fill"]->getStr() == "gradient") { double angle = (m_style["draw:angle"] ? m_style["draw:angle"]->getDouble() : 0.0); angle *= -1.0; while(angle < 0) angle += 360; while(angle > 360) angle -= 360; if (!gradient.count()) { if (propList["draw:style"] && (propList["draw:style"]->getStr() == "radial" || propList["draw:style"]->getStr() == "rectangular" || propList["draw:style"]->getStr() == "square" || propList["draw:style"]->getStr() == "ellipsoid")) { m_outputSink << "\n"; m_outputSink << " getStr().cstr() << "\""; else if (propList["draw:cx"]) m_outputSink << " cx=\"" << propList["draw:cx"]->getStr().cstr() << "\""; if (propList["svg:cy"]) m_outputSink << " cy=\"" << propList["svg:cy"]->getStr().cstr() << "\""; else if (propList["draw:cy"]) m_outputSink << " cy=\"" << propList["draw:cy"]->getStr().cstr() << "\""; m_outputSink << " r=\"" << (1 - (propList["draw:border"] ? propList["draw:border"]->getDouble() : 0))*100.0 << "%\" >\n"; m_outputSink << " >\n"; if (propList["draw:start-color"] && propList["draw:end-color"]) { m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:end-opacity"] ? propList["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:start-opacity"] ? propList["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; } m_outputSink << " \n"; m_outputSink << "\n"; } else if (propList["draw:style"] && propList["draw:style"]->getStr() == "linear") { m_outputSink << "\n"; m_outputSink << " \n"; if (propList["draw:start-color"] && propList["draw:end-color"]) { m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:start-opacity"] ? propList["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:end-opacity"] ? propList["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; } m_outputSink << " \n"; // not a simple horizontal gradient if(angle != 270) { m_outputSink << " \n"; m_outputSink << " \n"; } m_outputSink << "\n"; } else if (propList["draw:style"] && propList["draw:style"]->getStr() == "axial") { m_outputSink << "\n"; m_outputSink << " \n"; if (propList["draw:start-color"] && propList["draw:end-color"]) { m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:end-opacity"] ? propList["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:start-opacity"] ? propList["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl; m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << (propList["libwpg:end-opacity"] ? propList["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl; } m_outputSink << " \n"; // not a simple horizontal gradient if(angle != 270) { m_outputSink << " \n"; m_outputSink << " \n"; } m_outputSink << "\n"; } } else { if (propList["draw:style"] && propList["draw:style"]->getStr() == "radial") { m_outputSink << "\n"; m_outputSink << " getStr().cstr() << "\" cy=\"" << propList["svg:cy"]->getStr().cstr() << "\" r=\"" << propList["svg:r"]->getStr().cstr() << "\" >\n"; for(unsigned c = 0; c < m_gradient.count(); c++) { m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-color=\"" << m_gradient[c]["svg:stop-color"]->getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << m_gradient[c]["svg:stop-opacity"]->getDouble() << "\" />" << std::endl; } m_outputSink << " \n"; m_outputSink << "\n"; } else { m_outputSink << "\n"; m_outputSink << " \n"; for(unsigned c = 0; c < m_gradient.count(); c++) { m_outputSink << " getStr().cstr() << "\""; m_outputSink << " stop-color=\"" << m_gradient[c]["svg:stop-color"]->getStr().cstr() << "\""; m_outputSink << " stop-opacity=\"" << m_gradient[c]["svg:stop-opacity"]->getDouble() << "\" />" << std::endl; } m_outputSink << " \n"; // not a simple horizontal gradient if(angle != 270) { m_outputSink << " \n"; m_outputSink << " \n"; } m_outputSink << "\n"; } } } } void libwpg::WPGSVGGenerator::startLayer(const ::WPXPropertyList& propList) { m_outputSink << "getInt() << "\""; if (propList["svg:fill-rule"]) m_outputSink << " fill-rule=\"" << propList["svg:fill-rule"]->getStr().cstr() << "\""; m_outputSink << " >\n"; } void libwpg::WPGSVGGenerator::endLayer() { m_outputSink << "\n"; } void libwpg::WPGSVGGenerator::drawRectangle(const ::WPXPropertyList& propList) { m_outputSink << "getDouble()) << "\" y=\"" << doubleToString(72*propList["svg:y"]->getDouble()) << "\" "; m_outputSink << "width=\"" << doubleToString(72*propList["svg:width"]->getDouble()) << "\" height=\"" << doubleToString(72*propList["svg:height"]->getDouble()) << "\" "; if((propList["svg:rx"] && propList["svg:rx"]->getInt() !=0) || (propList["svg:ry"] && propList["svg:ry"]->getInt() !=0)) m_outputSink << "rx=\"" << doubleToString(72*propList["svg:rx"]->getDouble()) << "\" ry=\"" << doubleToString(72*propList["svg:ry"]->getDouble()) << "\" "; writeStyle(); m_outputSink << "/>\n"; } void libwpg::WPGSVGGenerator::drawEllipse(const WPXPropertyList& propList) { m_outputSink << "getDouble()) << "\" cy=\"" << doubleToString(72*propList["svg:cy"]->getDouble()) << "\" "; m_outputSink << "rx=\"" << doubleToString(72*propList["svg:rx"]->getDouble()) << "\" ry=\"" << doubleToString(72*propList["svg:ry"]->getDouble()) << "\" "; writeStyle(); if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0) m_outputSink << " transform=\" translate(" << doubleToString(72*propList["svg:cx"]->getDouble()) << ", " << doubleToString(72*propList["svg:cy"]->getDouble()) << ") rotate(" << doubleToString(-propList["libwpg:rotate"]->getDouble()) << ") translate(" << doubleToString(-72*propList["svg:cx"]->getDouble()) << ", " << doubleToString(-72*propList["svg:cy"]->getDouble()) << ")\" "; m_outputSink << "/>\n"; } void libwpg::WPGSVGGenerator::drawPolyline(const ::WPXPropertyListVector& vertices) { drawPolySomething(vertices, false); } void libwpg::WPGSVGGenerator::drawPolygon(const ::WPXPropertyListVector& vertices) { drawPolySomething(vertices, true); } void libwpg::WPGSVGGenerator::drawPolySomething(const ::WPXPropertyListVector& vertices, bool isClosed) { if(vertices.count() < 2) return; if(vertices.count() == 2) { m_outputSink << "getDouble())) << "\" y1=\"" << doubleToString(72*(vertices[0]["svg:y"]->getDouble())) << "\" "; m_outputSink << "x2=\"" << doubleToString(72*(vertices[1]["svg:x"]->getDouble())) << "\" y2=\"" << doubleToString(72*(vertices[1]["svg:y"]->getDouble())) << "\"\n"; writeStyle(); m_outputSink << "/>\n"; } else { if (isClosed) m_outputSink << "getDouble())) << " " << doubleToString(72*(vertices[i]["svg:y"]->getDouble())); if (i < vertices.count()-1) m_outputSink << ", "; } m_outputSink << "\"\n"; writeStyle(isClosed); m_outputSink << "/>\n"; } } void libwpg::WPGSVGGenerator::drawPath(const ::WPXPropertyListVector& path) { m_outputSink << "getStr() == "M") { m_outputSink << "\nM"; m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble())); } else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "L") { m_outputSink << "\nL"; m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble())); } else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "C") { m_outputSink << "\nC"; m_outputSink << doubleToString(72*(propList["svg:x1"]->getDouble())) << "," << doubleToString(72*(propList["svg:y1"]->getDouble())) << " "; m_outputSink << doubleToString(72*(propList["svg:x2"]->getDouble())) << "," << doubleToString(72*(propList["svg:y2"]->getDouble())) << " "; m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble())); } else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "A") { m_outputSink << "\nA"; m_outputSink << doubleToString(72*(propList["svg:rx"]->getDouble())) << "," << doubleToString(72*(propList["svg:ry"]->getDouble())) << " "; m_outputSink << doubleToString(propList["libwpg:rotate"] ? propList["libwpg:rotate"]->getDouble() : 0) << " "; m_outputSink << (propList["libwpg:large-arc"] ? propList["libwpg:large-arc"]->getInt() : 1) << ","; m_outputSink << (propList["libwpg:sweep"] ? propList["libwpg:sweep"]->getInt() : 1) << " "; m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble())); } else if ((i >= path.count()-1 && i > 2) && propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "Z" ) { isClosed = true; m_outputSink << "\nZ"; } } m_outputSink << "\" \n"; writeStyle(isClosed); m_outputSink << "/>\n"; } void libwpg::WPGSVGGenerator::drawGraphicObject(const ::WPXPropertyList &propList, const ::WPXBinaryData& binaryData) { if (!propList["libwpg:mime-type"] || propList["libwpg:mime-type"]->getStr().len() <= 0) return; WPXString base64 = binaryData.getBase64Data(); m_outputSink << "getDouble())) << "\" y=\"" << doubleToString(72*(propList["svg:y"]->getDouble())) << "\" "; m_outputSink << "width=\"" << doubleToString(72*(propList["svg:width"]->getDouble())) << "\" height=\"" << doubleToString(72*(propList["svg:height"]->getDouble())) << "\" "; m_outputSink << "xlink:href=\"data:" << propList["libwpg:mime-type"]->getStr().cstr() << ";base64,"; m_outputSink << base64.cstr(); m_outputSink << "\" />\n"; } void libwpg::WPGSVGGenerator::startTextObject(const ::WPXPropertyList &propList, const ::WPXPropertyListVector & /* path */) { m_outputSink << "getDouble())) << "\" y=\"" << doubleToString(72*(propList["svg:y"]->getDouble())) << "\""; if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0) m_outputSink << " transform=\"translate(" << doubleToString(72*propList["svg:x"]->getDouble()) << ", " << doubleToString(72*propList["svg:y"]->getDouble()) << ") rotate(" << doubleToString(-propList["libwpg:rotate"]->getDouble()) << ") translate(" << doubleToString(-72*propList["svg:x"]->getDouble()) << ", " << doubleToString(-72*propList["svg:y"]->getDouble()) << ")\""; m_outputSink << ">\n"; } void libwpg::WPGSVGGenerator::endTextObject() { m_outputSink << "\n"; } void libwpg::WPGSVGGenerator::startTextSpan(const ::WPXPropertyList &propList) { m_outputSink << "getStr().cstr() << "\" "; if (propList["fo:font-style"]) m_outputSink << "font-style=\"" << propList["fo:font-style"]->getStr().cstr() << "\" "; if (propList["fo:font-weight"]) m_outputSink << "font-weight=\"" << propList["fo:font-weight"]->getStr().cstr() << "\" "; if (propList["fo:font-variant"]) m_outputSink << "font-variant=\"" << propList["fo:font-variant"]->getStr().cstr() << "\" "; if (propList["fo:font-size"]) m_outputSink << "font-size=\"" << doubleToString(propList["fo:font-size"]->getDouble()) << "\" "; if (propList["fo:color"]) m_outputSink << "fill=\"" << propList["fo:color"]->getStr().cstr() << "\" "; if (propList["fo:text-transform"]) m_outputSink << "text-transform=\"" << propList["fo:text-transform"]->getStr().cstr() << "\" "; if (propList["svg:fill-opacity"]) m_outputSink << "fill-opacity=\"" << doubleToString(propList["svg:fill-opacity"]->getDouble()) << "\" "; if (propList["svg:stroke-opacity"]) m_outputSink << "stroke-opacity=\"" << doubleToString(propList["svg:stroke-opacity"]->getDouble()) << "\" "; m_outputSink << ">\n"; } void libwpg::WPGSVGGenerator::endTextSpan() { m_outputSink << "\n"; } void libwpg::WPGSVGGenerator::insertText(const ::WPXString &str) { WPXString tempUTF8(str, true); m_outputSink << tempUTF8.cstr() << "\n"; } // create "style" attribute based on current pen and brush void libwpg::WPGSVGGenerator::writeStyle(bool /* isClosed */) { m_outputSink << "style=\""; if (m_style["svg:stroke-width"]) m_outputSink << "stroke-width: " << doubleToString(72*m_style["svg:stroke-width"]->getDouble()) << "; "; if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() != "none") { if (m_style["svg:stroke-color"]) m_outputSink << "stroke: " << m_style["svg:stroke-color"]->getStr().cstr() << "; "; if(m_style["svg:stroke-opacity"] && m_style["svg:stroke-opacity"]->getInt()!= 1) m_outputSink << "stroke-opacity: " << doubleToString(m_style["svg:stroke-opacity"]->getDouble()) << "; "; } if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "solid") m_outputSink << "stroke-dasharray: solid; "; else if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "dash") { int dots1 = m_style["draw:dots1"]->getInt(); int dots2 = m_style["draw:dots2"]->getInt(); double dots1len = m_style["draw:dots1-length"]->getDouble(); double dots2len = m_style["draw:dots2-length"]->getDouble(); double gap = m_style["draw:distance"]->getDouble(); m_outputSink << "stroke-dasharray: "; for (int i = 0; i < dots1; i++) { if (i) m_outputSink << ", "; m_outputSink << (int)dots1len; m_outputSink << ", "; m_outputSink << (int)gap; } for (int j = 0; j < dots2; j++) { m_outputSink << ", "; m_outputSink << (int)dots2len; m_outputSink << ", "; m_outputSink << (int)gap; } m_outputSink << "; "; } if (m_style["svg:stroke-linecap"]) m_outputSink << "stroke-linecap: " << m_style["svg:stroke-linecap"]->getStr().cstr() << "; "; if (m_style["svg:stroke-linejoin"]) m_outputSink << "stroke-linejoin: " << m_style["svg:stroke-linejoin"]->getStr().cstr() << "; "; if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none") m_outputSink << "fill: none; "; else if(m_style["svg:fill-rule"]) m_outputSink << "fill-rule: " << m_style["svg:fill-rule"]->getStr().cstr() << "; "; if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "gradient") m_outputSink << "fill: url(#grad" << m_gradientIndex-1 << "); "; if(m_style["draw:shadow"] && m_style["draw:shadow"]->getStr() == "visible") m_outputSink << "filter:url(#shadow" << m_shadowIndex-1 << "); "; if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "solid") if (m_style["draw:fill-color"]) m_outputSink << "fill: " << m_style["draw:fill-color"]->getStr().cstr() << "; "; if(m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1) m_outputSink << "fill-opacity: " << doubleToString(m_style["draw:opacity"]->getDouble()) << "; "; m_outputSink << "\""; // style }