Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* libmspub
3 : * Version: MPL 1.1 / GPLv2+ / LGPLv2+
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License or as specified alternatively below. You may obtain a copy of
8 : * the License at http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * Major Contributor(s):
16 : * Copyright (C) 2012 Fridrich Strba <fridrich.strba@bluewin.ch>
17 : * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
18 : *
19 : * All Rights Reserved.
20 : *
21 : * For minor contributions see the git repository.
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
25 : * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
26 : * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
27 : * instead of those above.
28 : */
29 :
30 : #include "MSPUBSVGGenerator.h"
31 : #include "libmspub.h"
32 : #include <locale.h>
33 : #include <sstream>
34 : #include <string>
35 :
36 0 : static std::string doubleToString(const double value)
37 : {
38 0 : std::ostringstream tempStream;
39 0 : tempStream << value;
40 : #ifndef __ANDROID__
41 0 : std::string decimalPoint(localeconv()->decimal_point);
42 : #else
43 : std::string decimalPoint(".");
44 : #endif
45 0 : if ((decimalPoint.size() == 0) || (decimalPoint == "."))
46 0 : return tempStream.str();
47 0 : std::string stringValue(tempStream.str());
48 0 : if (!stringValue.empty())
49 : {
50 : std::string::size_type pos;
51 0 : while ((pos = stringValue.find(decimalPoint)) != std::string::npos)
52 0 : stringValue.replace(pos,decimalPoint.size(),".");
53 : }
54 0 : return stringValue;
55 : }
56 :
57 0 : static unsigned stringToColour(const ::WPXString &s)
58 : {
59 0 : std::string str(s.cstr());
60 0 : if (str[0] == '#')
61 : {
62 0 : if (str.length() != 7)
63 0 : return 0;
64 : else
65 0 : str.erase(str.begin());
66 : }
67 : else
68 0 : return 0;
69 :
70 0 : std::istringstream istr(str);
71 0 : unsigned val = 0;
72 0 : istr >> std::hex >> val;
73 0 : return val;
74 : }
75 :
76 0 : libmspub::MSPUBSVGGenerator::MSPUBSVGGenerator(libmspub::MSPUBStringVector &vec): m_gradient(), m_style(), m_gradientIndex(1), m_patternIndex(1), m_shadowIndex(1), m_outputSink(), m_vec(vec)
77 : {
78 0 : }
79 :
80 0 : libmspub::MSPUBSVGGenerator::~MSPUBSVGGenerator()
81 : {
82 0 : }
83 :
84 0 : void libmspub::MSPUBSVGGenerator::startGraphics(const WPXPropertyList &propList)
85 : {
86 0 : m_outputSink << "<svg:svg version=\"1.1\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ";
87 0 : if (propList["svg:width"])
88 0 : m_outputSink << "width=\"" << doubleToString(72*(propList["svg:width"]->getDouble())) << "\" ";
89 0 : if (propList["svg:height"])
90 0 : m_outputSink << "height=\"" << doubleToString(72*(propList["svg:height"]->getDouble())) << "\"";
91 0 : m_outputSink << " >\n";
92 0 : }
93 :
94 0 : void libmspub::MSPUBSVGGenerator::endGraphics()
95 : {
96 0 : m_outputSink << "</svg:svg>\n";
97 0 : m_vec.append(m_outputSink.str().c_str());
98 0 : m_outputSink.str("");
99 0 : }
100 :
101 0 : void libmspub::MSPUBSVGGenerator::setStyle(const ::WPXPropertyList &propList, const ::WPXPropertyListVector &gradient)
102 : {
103 0 : m_style.clear();
104 0 : m_style = propList;
105 :
106 0 : m_gradient = gradient;
107 0 : if(m_style["draw:shadow"] && m_style["draw:shadow"]->getStr() == "visible")
108 : {
109 0 : double shadowRed = 0.0;
110 0 : double shadowGreen = 0.0;
111 0 : double shadowBlue = 0.0;
112 0 : if (m_style["draw:shadow-color"])
113 : {
114 0 : unsigned shadowColour = stringToColour(m_style["draw:shadow-color"]->getStr());
115 0 : shadowRed = (double)((shadowColour & 0x00ff0000) >> 16)/255.0;
116 0 : shadowGreen = (double)((shadowColour & 0x0000ff00) >> 8)/255.0;
117 0 : shadowBlue = (double)(shadowColour & 0x000000ff)/255.0;
118 : }
119 0 : m_outputSink << "<svg:defs>\n";
120 0 : m_outputSink << "<svg:filter filterUnits=\"userSpaceOnUse\" id=\"shadow" << m_shadowIndex++ << "\">";
121 0 : m_outputSink << "<svg:feOffset in=\"SourceGraphic\" result=\"offset\" ";
122 0 : m_outputSink << "dx=\"" << doubleToString(72*m_style["draw:shadow-offset-x"]->getDouble()) << "\" ";
123 0 : m_outputSink << "dy=\"" << doubleToString(72*m_style["draw:shadow-offset-y"]->getDouble()) << "\"/>";
124 0 : m_outputSink << "<svg:feColorMatrix in=\"offset\" result=\"offset-color\" type=\"matrix\" values=\"";
125 0 : m_outputSink << "0 0 0 0 " << doubleToString(shadowRed) ;
126 0 : m_outputSink << " 0 0 0 0 " << doubleToString(shadowGreen);
127 0 : m_outputSink << " 0 0 0 0 " << doubleToString(shadowBlue);
128 0 : if(m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1)
129 0 : m_outputSink << " 0 0 0 " << doubleToString(m_style["draw:shadow-opacity"]->getDouble()/m_style["draw:opacity"]->getDouble()) << " 0\"/>";
130 : else
131 0 : m_outputSink << " 0 0 0 " << doubleToString(m_style["draw:shadow-opacity"]->getDouble()) << " 0\"/>";
132 0 : m_outputSink << "<svg:feMerge><svg:feMergeNode in=\"offset-color\" /><svg:feMergeNode in=\"SourceGraphic\" /></svg:feMerge></svg:filter></svg:defs>";
133 : }
134 :
135 0 : if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "gradient")
136 : {
137 0 : double angle = (m_style["draw:angle"] ? m_style["draw:angle"]->getDouble() : 0.0);
138 0 : angle *= -1.0;
139 0 : while(angle < 0)
140 0 : angle += 360;
141 0 : while(angle > 360)
142 0 : angle -= 360;
143 :
144 0 : if (!m_gradient.count())
145 : {
146 0 : if (m_style["draw:style"] &&
147 0 : (m_style["draw:style"]->getStr() == "radial" ||
148 0 : m_style["draw:style"]->getStr() == "rectangular" ||
149 0 : m_style["draw:style"]->getStr() == "square" ||
150 0 : m_style["draw:style"]->getStr() == "ellipsoid"))
151 : {
152 0 : m_outputSink << "<svg:defs>\n";
153 0 : m_outputSink << " <svg:radialGradient id=\"grad" << m_gradientIndex++ << "\"";
154 :
155 0 : if (m_style["svg:cx"])
156 0 : m_outputSink << " cx=\"" << m_style["svg:cx"]->getStr().cstr() << "\"";
157 0 : else if (m_style["draw:cx"])
158 0 : m_outputSink << " cx=\"" << m_style["draw:cx"]->getStr().cstr() << "\"";
159 :
160 0 : if (m_style["svg:cy"])
161 0 : m_outputSink << " cy=\"" << m_style["svg:cy"]->getStr().cstr() << "\"";
162 0 : else if (m_style["draw:cy"])
163 0 : m_outputSink << " cy=\"" << m_style["draw:cy"]->getStr().cstr() << "\"";
164 0 : m_outputSink << " r=\"" << (1 - (m_style["draw:border"] ? m_style["draw:border"]->getDouble() : 0))*100.0 << "%\" >\n";
165 0 : m_outputSink << " >\n";
166 :
167 0 : if (m_style["draw:start-color"] && m_style["draw:end-color"])
168 : {
169 0 : m_outputSink << " <svg:stop offset=\"0%\"";
170 0 : m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\"";
171 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:end-opacity"] ? m_style["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl;
172 :
173 0 : m_outputSink << " <svg:stop offset=\"100%\"";
174 0 : m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\"";
175 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:start-opacity"] ? m_style["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl;
176 : }
177 0 : m_outputSink << " </svg:radialGradient>\n";
178 0 : m_outputSink << "</svg:defs>\n";
179 : }
180 0 : else if (m_style["draw:style"] && m_style["draw:style"]->getStr() == "linear")
181 : {
182 0 : m_outputSink << "<svg:defs>\n";
183 0 : m_outputSink << " <svg:linearGradient id=\"grad" << m_gradientIndex++ << "\" >\n";
184 :
185 0 : if (m_style["draw:start-color"] && m_style["draw:end-color"])
186 : {
187 0 : m_outputSink << " <svg:stop offset=\"0%\"";
188 0 : m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\"";
189 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:start-opacity"] ? m_style["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl;
190 :
191 0 : m_outputSink << " <svg:stop offset=\"100%\"";
192 0 : m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\"";
193 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:end-opacity"] ? m_style["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl;
194 : }
195 0 : m_outputSink << " </svg:linearGradient>\n";
196 :
197 : // not a simple horizontal gradient
198 0 : if(angle != 270)
199 : {
200 0 : m_outputSink << " <svg:linearGradient xlink:href=\"#grad" << m_gradientIndex-1 << "\"";
201 0 : m_outputSink << " id=\"grad" << m_gradientIndex++ << "\" ";
202 0 : m_outputSink << "x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\" ";
203 0 : m_outputSink << "gradientTransform=\"rotate(" << angle << " .5 .5)\" ";
204 0 : m_outputSink << "gradientUnits=\"objectBoundingBox\" >\n";
205 0 : m_outputSink << " </svg:linearGradient>\n";
206 : }
207 :
208 0 : m_outputSink << "</svg:defs>\n";
209 : }
210 0 : else if (m_style["draw:style"] && m_style["draw:style"]->getStr() == "axial")
211 : {
212 0 : m_outputSink << "<svg:defs>\n";
213 0 : m_outputSink << " <svg:linearGradient id=\"grad" << m_gradientIndex++ << "\" >\n";
214 :
215 0 : if (m_style["draw:start-color"] && m_style["draw:end-color"])
216 : {
217 0 : m_outputSink << " <svg:stop offset=\"0%\"";
218 0 : m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\"";
219 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:end-opacity"] ? m_style["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl;
220 :
221 0 : m_outputSink << " <svg:stop offset=\"50%\"";
222 0 : m_outputSink << " stop-color=\"" << m_style["draw:start-color"]->getStr().cstr() << "\"";
223 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:start-opacity"] ? m_style["libwpg:start-opacity"]->getDouble() : 1) << "\" />" << std::endl;
224 :
225 0 : m_outputSink << " <svg:stop offset=\"100%\"";
226 0 : m_outputSink << " stop-color=\"" << m_style["draw:end-color"]->getStr().cstr() << "\"";
227 0 : m_outputSink << " stop-opacity=\"" << (m_style["libwpg:end-opacity"] ? m_style["libwpg:end-opacity"]->getDouble() : 1) << "\" />" << std::endl;
228 : }
229 0 : m_outputSink << " </svg:linearGradient>\n";
230 :
231 : // not a simple horizontal gradient
232 0 : if(angle != 270)
233 : {
234 0 : m_outputSink << " <svg:linearGradient xlink:href=\"#grad" << m_gradientIndex-1 << "\"";
235 0 : m_outputSink << " id=\"grad" << m_gradientIndex++ << "\" ";
236 0 : m_outputSink << "x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\" ";
237 0 : m_outputSink << "gradientTransform=\"rotate(" << angle << " .5 .5)\" ";
238 0 : m_outputSink << "gradientUnits=\"objectBoundingBox\" >\n";
239 0 : m_outputSink << " </svg:linearGradient>\n";
240 : }
241 :
242 0 : m_outputSink << "</svg:defs>\n";
243 : }
244 : }
245 : else
246 : {
247 0 : if (m_style["draw:style"] && m_style["draw:style"]->getStr() == "radial")
248 : {
249 0 : m_outputSink << "<svg:defs>\n";
250 0 : m_outputSink << " <svg:radialGradient id=\"grad" << m_gradientIndex++ << "\" cx=\"" << m_style["svg:cx"]->getStr().cstr() << "\" cy=\"" << m_style["svg:cy"]->getStr().cstr() << "\" r=\"" << m_style["svg:r"]->getStr().cstr() << "\" >\n";
251 0 : for(unsigned c = 0; c < m_gradient.count(); c++)
252 : {
253 0 : m_outputSink << " <svg:stop offset=\"" << m_gradient[c]["svg:offset"]->getStr().cstr() << "\"";
254 :
255 0 : m_outputSink << " stop-color=\"" << m_gradient[c]["svg:stop-color"]->getStr().cstr() << "\"";
256 0 : m_outputSink << " stop-opacity=\"" << m_gradient[c]["svg:stop-opacity"]->getDouble() << "\" />" << std::endl;
257 :
258 : }
259 0 : m_outputSink << " </svg:radialGradient>\n";
260 0 : m_outputSink << "</svg:defs>\n";
261 : }
262 : else
263 : {
264 0 : m_outputSink << "<svg:defs>\n";
265 0 : m_outputSink << " <svg:linearGradient id=\"grad" << m_gradientIndex++ << "\" >\n";
266 0 : for(unsigned c = 0; c < m_gradient.count(); c++)
267 : {
268 0 : m_outputSink << " <svg:stop offset=\"" << m_gradient[c]["svg:offset"]->getStr().cstr() << "\"";
269 :
270 0 : m_outputSink << " stop-color=\"" << m_gradient[c]["svg:stop-color"]->getStr().cstr() << "\"";
271 0 : m_outputSink << " stop-opacity=\"" << m_gradient[c]["svg:stop-opacity"]->getDouble() << "\" />" << std::endl;
272 :
273 : }
274 0 : m_outputSink << " </svg:linearGradient>\n";
275 :
276 : // not a simple horizontal gradient
277 0 : if(angle != 270)
278 : {
279 0 : m_outputSink << " <svg:linearGradient xlink:href=\"#grad" << m_gradientIndex-1 << "\"";
280 0 : m_outputSink << " id=\"grad" << m_gradientIndex++ << "\" ";
281 0 : m_outputSink << "x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\" ";
282 0 : m_outputSink << "gradientTransform=\"rotate(" << angle << " .5 .5)\" ";
283 0 : m_outputSink << "gradientUnits=\"objectBoundingBox\" >\n";
284 0 : m_outputSink << " </svg:linearGradient>\n";
285 : }
286 :
287 0 : m_outputSink << "</svg:defs>\n";
288 : }
289 : }
290 : }
291 0 : else if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "bitmap")
292 : {
293 0 : if (m_style["draw:fill-image"] && m_style["libwpg:mime-type"])
294 : {
295 0 : m_outputSink << "<svg:defs>\n";
296 0 : m_outputSink << " <svg:pattern id=\"img" << m_patternIndex++ << "\" patternUnits=\"userSpaceOnUse\" ";
297 0 : if (m_style["svg:width"])
298 0 : m_outputSink << "width=\"" << doubleToString(72*(m_style["svg:width"]->getDouble())) << "\" ";
299 : else
300 0 : m_outputSink << "width=\"100\" ";
301 :
302 0 : if (m_style["svg:height"])
303 0 : m_outputSink << "height=\"" << doubleToString(72*(m_style["svg:height"]->getDouble())) << "\">" << std::endl;
304 : else
305 0 : m_outputSink << "height=\"100\">" << std::endl;
306 0 : m_outputSink << "<svg:image ";
307 :
308 0 : if (m_style["svg:x"])
309 0 : m_outputSink << "x=\"" << doubleToString(72*(m_style["svg:x"]->getDouble())) << "\" ";
310 : else
311 0 : m_outputSink << "x=\"0\" ";
312 :
313 0 : if (m_style["svg:y"])
314 0 : m_outputSink << "y=\"" << doubleToString(72*(m_style["svg:y"]->getDouble())) << "\" ";
315 : else
316 0 : m_outputSink << "y=\"0\" ";
317 :
318 0 : if (m_style["svg:width"])
319 0 : m_outputSink << "width=\"" << doubleToString(72*(m_style["svg:width"]->getDouble())) << "\" ";
320 : else
321 0 : m_outputSink << "width=\"100\" ";
322 :
323 0 : if (m_style["svg:height"])
324 0 : m_outputSink << "height=\"" << doubleToString(72*(m_style["svg:height"]->getDouble())) << "\" ";
325 : else
326 0 : m_outputSink << "height=\"100\" ";
327 :
328 0 : m_outputSink << "xlink:href=\"data:" << m_style["libwpg:mime-type"]->getStr().cstr() << ";base64,";
329 0 : m_outputSink << m_style["draw:fill-image"]->getStr().cstr();
330 0 : m_outputSink << "\" />\n";
331 0 : m_outputSink << " </svg:pattern>\n";
332 0 : m_outputSink << "</svg:defs>\n";
333 : }
334 : }
335 0 : }
336 :
337 0 : void libmspub::MSPUBSVGGenerator::startLayer(const ::WPXPropertyList &propList)
338 : {
339 0 : m_outputSink << "<svg:g";
340 0 : if (propList["svg:id"])
341 0 : m_outputSink << " id=\"Layer" << propList["svg:id"]->getStr().cstr() << "\"";
342 0 : if (propList["svg:fill-rule"])
343 0 : m_outputSink << " fill-rule=\"" << propList["svg:fill-rule"]->getStr().cstr() << "\"";
344 0 : m_outputSink << " >\n";
345 0 : }
346 :
347 0 : void libmspub::MSPUBSVGGenerator::endLayer()
348 : {
349 0 : m_outputSink << "</svg:g>\n";
350 0 : }
351 :
352 0 : void libmspub::MSPUBSVGGenerator::drawRectangle(const ::WPXPropertyList &propList)
353 : {
354 0 : m_outputSink << "<svg:rect ";
355 0 : m_outputSink << "x=\"" << doubleToString(72*propList["svg:x"]->getDouble()) << "\" y=\"" << doubleToString(72*propList["svg:y"]->getDouble()) << "\" ";
356 0 : m_outputSink << "width=\"" << doubleToString(72*propList["svg:width"]->getDouble()) << "\" height=\"" << doubleToString(72*propList["svg:height"]->getDouble()) << "\" ";
357 0 : if((propList["svg:rx"] && propList["svg:rx"]->getInt() !=0) || (propList["svg:ry"] && propList["svg:ry"]->getInt() !=0))
358 0 : m_outputSink << "rx=\"" << doubleToString(72*propList["svg:rx"]->getDouble()) << "\" ry=\"" << doubleToString(72*propList["svg:ry"]->getDouble()) << "\" ";
359 0 : writeStyle();
360 0 : m_outputSink << "/>\n";
361 0 : }
362 :
363 0 : void libmspub::MSPUBSVGGenerator::drawEllipse(const WPXPropertyList &propList)
364 : {
365 0 : m_outputSink << "<svg:ellipse ";
366 0 : m_outputSink << "cx=\"" << doubleToString(72*propList["svg:cx"]->getDouble()) << "\" cy=\"" << doubleToString(72*propList["svg:cy"]->getDouble()) << "\" ";
367 0 : m_outputSink << "rx=\"" << doubleToString(72*propList["svg:rx"]->getDouble()) << "\" ry=\"" << doubleToString(72*propList["svg:ry"]->getDouble()) << "\" ";
368 0 : writeStyle();
369 0 : if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0)
370 0 : m_outputSink << " transform=\" translate(" << doubleToString(72*propList["svg:cx"]->getDouble()) << ", " << doubleToString(72*propList["svg:cy"]->getDouble())
371 0 : << ") rotate(" << doubleToString(-propList["libwpg:rotate"]->getDouble())
372 0 : << ") translate(" << doubleToString(-72*propList["svg:cx"]->getDouble())
373 0 : << ", " << doubleToString(-72*propList["svg:cy"]->getDouble())
374 0 : << ")\" ";
375 0 : m_outputSink << "/>\n";
376 0 : }
377 :
378 0 : void libmspub::MSPUBSVGGenerator::drawPolyline(const ::WPXPropertyListVector &vertices)
379 : {
380 0 : drawPolySomething(vertices, false);
381 0 : }
382 :
383 0 : void libmspub::MSPUBSVGGenerator::drawPolygon(const ::WPXPropertyListVector &vertices)
384 : {
385 0 : drawPolySomething(vertices, true);
386 0 : }
387 :
388 0 : void libmspub::MSPUBSVGGenerator::drawPolySomething(const ::WPXPropertyListVector &vertices, bool isClosed)
389 : {
390 0 : if(vertices.count() < 2)
391 0 : return;
392 :
393 0 : if(vertices.count() == 2)
394 : {
395 0 : m_outputSink << "<svg:line ";
396 0 : m_outputSink << "x1=\"" << doubleToString(72*(vertices[0]["svg:x"]->getDouble())) << "\" y1=\"" << doubleToString(72*(vertices[0]["svg:y"]->getDouble())) << "\" ";
397 0 : m_outputSink << "x2=\"" << doubleToString(72*(vertices[1]["svg:x"]->getDouble())) << "\" y2=\"" << doubleToString(72*(vertices[1]["svg:y"]->getDouble())) << "\"\n";
398 0 : writeStyle();
399 0 : m_outputSink << "/>\n";
400 : }
401 : else
402 : {
403 0 : if (isClosed)
404 0 : m_outputSink << "<svg:polygon ";
405 : else
406 0 : m_outputSink << "<svg:polyline ";
407 :
408 0 : m_outputSink << "points=\"";
409 0 : for(unsigned i = 0; i < vertices.count(); i++)
410 : {
411 0 : m_outputSink << doubleToString(72*(vertices[i]["svg:x"]->getDouble())) << " " << doubleToString(72*(vertices[i]["svg:y"]->getDouble()));
412 0 : if (i < vertices.count()-1)
413 0 : m_outputSink << ", ";
414 : }
415 0 : m_outputSink << "\"\n";
416 0 : writeStyle(isClosed);
417 0 : m_outputSink << "/>\n";
418 : }
419 : }
420 :
421 0 : void libmspub::MSPUBSVGGenerator::drawPath(const ::WPXPropertyListVector &path)
422 : {
423 0 : m_outputSink << "<svg:path d=\" ";
424 0 : bool isClosed = false;
425 0 : unsigned i=0;
426 0 : for(i=0; i < path.count(); i++)
427 : {
428 0 : WPXPropertyList propList = path[i];
429 0 : if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "M")
430 : {
431 0 : m_outputSink << "\nM";
432 0 : m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble()));
433 : }
434 0 : else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "L")
435 : {
436 0 : m_outputSink << "\nL";
437 0 : m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble()));
438 : }
439 0 : else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "C")
440 : {
441 0 : m_outputSink << "\nC";
442 0 : m_outputSink << doubleToString(72*(propList["svg:x1"]->getDouble())) << "," << doubleToString(72*(propList["svg:y1"]->getDouble())) << " ";
443 0 : m_outputSink << doubleToString(72*(propList["svg:x2"]->getDouble())) << "," << doubleToString(72*(propList["svg:y2"]->getDouble())) << " ";
444 0 : m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble()));
445 : }
446 0 : else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "Q")
447 : {
448 0 : m_outputSink << "\nQ";
449 0 : m_outputSink << doubleToString(72*(propList["svg:x1"]->getDouble())) << "," << doubleToString(72*(propList["svg:y1"]->getDouble())) << " ";
450 0 : m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble()));
451 : }
452 0 : else if (propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "A")
453 : {
454 0 : m_outputSink << "\nA";
455 0 : m_outputSink << doubleToString(72*(propList["svg:rx"]->getDouble())) << "," << doubleToString(72*(propList["svg:ry"]->getDouble())) << " ";
456 0 : m_outputSink << doubleToString(propList["libwpg:rotate"] ? propList["libwpg:rotate"]->getDouble() : 0) << " ";
457 0 : m_outputSink << (propList["libwpg:large-arc"] ? propList["libwpg:large-arc"]->getInt() : 1) << ",";
458 0 : m_outputSink << (propList["libwpg:sweep"] ? propList["libwpg:sweep"]->getInt() : 1) << " ";
459 0 : m_outputSink << doubleToString(72*(propList["svg:x"]->getDouble())) << "," << doubleToString(72*(propList["svg:y"]->getDouble()));
460 : }
461 0 : else if ((i >= path.count()-1 && i > 2) && propList["libwpg:path-action"] && propList["libwpg:path-action"]->getStr() == "Z" )
462 : {
463 0 : isClosed = true;
464 0 : m_outputSink << "\nZ";
465 : }
466 0 : }
467 :
468 0 : m_outputSink << "\" \n";
469 0 : writeStyle(isClosed);
470 0 : m_outputSink << "/>\n";
471 0 : }
472 :
473 0 : void libmspub::MSPUBSVGGenerator::drawGraphicObject(const ::WPXPropertyList &propList, const ::WPXBinaryData &binaryData)
474 : {
475 0 : if (!propList["libwpg:mime-type"] || propList["libwpg:mime-type"]->getStr().len() <= 0)
476 0 : return;
477 0 : WPXString base64 = binaryData.getBase64Data();
478 0 : m_outputSink << "<svg:image ";
479 0 : if (propList["svg:x"] && propList["svg:y"] && propList["svg:width"] && propList["svg:height"])
480 : {
481 0 : m_outputSink << "x=\"" << doubleToString(72*(propList["svg:x"]->getDouble())) << "\" y=\"" << doubleToString(72*(propList["svg:y"]->getDouble())) << "\" ";
482 0 : m_outputSink << "width=\"" << doubleToString(72*(propList["svg:width"]->getDouble())) << "\" height=\"" << doubleToString(72*(propList["svg:height"]->getDouble())) << "\" ";
483 : }
484 0 : m_outputSink << "xlink:href=\"data:" << propList["libwpg:mime-type"]->getStr().cstr() << ";base64,";
485 0 : m_outputSink << base64.cstr();
486 0 : m_outputSink << "\" />\n";
487 : }
488 :
489 0 : void libmspub::MSPUBSVGGenerator::startTextObject(const ::WPXPropertyList &propList, const ::WPXPropertyListVector & /* path */)
490 : {
491 0 : m_outputSink << "<svg:text ";
492 0 : if (propList["svg:x"] && propList["svg:y"])
493 0 : m_outputSink << "x=\"" << doubleToString(72*(propList["svg:x"]->getDouble())) << "\" y=\"" << doubleToString(72*(propList["svg:y"]->getDouble())) << "\"";
494 0 : if (propList["libwpg:rotate"] && propList["libwpg:rotate"]->getDouble() != 0.0)
495 0 : m_outputSink << " transform=\"translate(" << doubleToString(72*propList["svg:x"]->getDouble()) << ", " << doubleToString(72*propList["svg:y"]->getDouble())
496 0 : << ") rotate(" << doubleToString(-propList["libwpg:rotate"]->getDouble())
497 0 : << ") translate(" << doubleToString(-72*propList["svg:x"]->getDouble())
498 0 : << ", " << doubleToString(-72*propList["svg:y"]->getDouble())
499 0 : << ")\"";
500 0 : m_outputSink << ">\n";
501 :
502 0 : }
503 :
504 0 : void libmspub::MSPUBSVGGenerator::endTextObject()
505 : {
506 0 : m_outputSink << "</svg:text>\n";
507 0 : }
508 :
509 0 : void libmspub::MSPUBSVGGenerator::startTextSpan(const ::WPXPropertyList &propList)
510 : {
511 0 : m_outputSink << "<svg:tspan ";
512 0 : if (propList["style:font-name"])
513 0 : m_outputSink << "font-family=\"" << propList["style:font-name"]->getStr().cstr() << "\" ";
514 0 : if (propList["fo:font-style"])
515 0 : m_outputSink << "font-style=\"" << propList["fo:font-style"]->getStr().cstr() << "\" ";
516 0 : if (propList["fo:font-weight"])
517 0 : m_outputSink << "font-weight=\"" << propList["fo:font-weight"]->getStr().cstr() << "\" ";
518 0 : if (propList["fo:font-variant"])
519 0 : m_outputSink << "font-variant=\"" << propList["fo:font-variant"]->getStr().cstr() << "\" ";
520 0 : if (propList["fo:font-size"])
521 0 : m_outputSink << "font-size=\"" << doubleToString(propList["fo:font-size"]->getDouble()) << "\" ";
522 0 : if (propList["fo:color"])
523 0 : m_outputSink << "fill=\"" << propList["fo:color"]->getStr().cstr() << "\" ";
524 0 : if (propList["fo:text-transform"])
525 0 : m_outputSink << "text-transform=\"" << propList["fo:text-transform"]->getStr().cstr() << "\" ";
526 0 : if (propList["svg:fill-opacity"])
527 0 : m_outputSink << "fill-opacity=\"" << doubleToString(propList["svg:fill-opacity"]->getDouble()) << "\" ";
528 0 : if (propList["svg:stroke-opacity"])
529 0 : m_outputSink << "stroke-opacity=\"" << doubleToString(propList["svg:stroke-opacity"]->getDouble()) << "\" ";
530 0 : m_outputSink << ">\n";
531 0 : }
532 :
533 0 : void libmspub::MSPUBSVGGenerator::endTextSpan()
534 : {
535 0 : m_outputSink << "</svg:tspan>\n";
536 0 : }
537 :
538 0 : void libmspub::MSPUBSVGGenerator::insertText(const ::WPXString &str)
539 : {
540 0 : WPXString tempUTF8(str, true);
541 0 : m_outputSink << tempUTF8.cstr() << "\n";
542 0 : }
543 :
544 : // create "style" attribute based on current pen and brush
545 0 : void libmspub::MSPUBSVGGenerator::writeStyle(bool /* isClosed */)
546 : {
547 0 : m_outputSink << "style=\"";
548 :
549 0 : if (m_style["svg:stroke-width"])
550 : {
551 0 : double width = m_style["svg:stroke-width"]->getDouble();
552 0 : if (width == 0.0 && m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() != "none")
553 0 : width = 0.2 / 72.0; // reasonable hairline
554 0 : m_outputSink << "stroke-width: " << doubleToString(72*width) << "; ";
555 : }
556 0 : if ((m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() != "none"))
557 : {
558 0 : if (m_style["svg:stroke-color"])
559 0 : m_outputSink << "stroke: " << m_style["svg:stroke-color"]->getStr().cstr() << "; ";
560 0 : if(m_style["svg:stroke-opacity"] && m_style["svg:stroke-opacity"]->getInt()!= 1)
561 0 : m_outputSink << "stroke-opacity: " << doubleToString(m_style["svg:stroke-opacity"]->getDouble()) << "; ";
562 : }
563 :
564 0 : if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "solid")
565 0 : m_outputSink << "stroke-dasharray: solid; ";
566 0 : else if (m_style["draw:stroke"] && m_style["draw:stroke"]->getStr() == "dash")
567 : {
568 0 : int dots1 = m_style["draw:dots1"]->getInt();
569 0 : int dots2 = m_style["draw:dots2"]->getInt();
570 0 : double dots1len = m_style["draw:dots1-length"]->getDouble();
571 0 : double dots2len = m_style["draw:dots2-length"]->getDouble();
572 0 : double gap = m_style["draw:distance"]->getDouble();
573 0 : m_outputSink << "stroke-dasharray: ";
574 0 : for (int i = 0; i < dots1; i++)
575 : {
576 0 : if (i)
577 0 : m_outputSink << ", ";
578 0 : m_outputSink << (int)dots1len;
579 0 : m_outputSink << ", ";
580 0 : m_outputSink << (int)gap;
581 : }
582 0 : for (int j = 0; j < dots2; j++)
583 : {
584 0 : m_outputSink << ", ";
585 0 : m_outputSink << (int)dots2len;
586 0 : m_outputSink << ", ";
587 0 : m_outputSink << (int)gap;
588 : }
589 0 : m_outputSink << "; ";
590 : }
591 :
592 0 : if (m_style["svg:stroke-linecap"])
593 0 : m_outputSink << "stroke-linecap: " << m_style["svg:stroke-linecap"]->getStr().cstr() << "; ";
594 :
595 0 : if (m_style["svg:stroke-linejoin"])
596 0 : m_outputSink << "stroke-linejoin: " << m_style["svg:stroke-linejoin"]->getStr().cstr() << "; ";
597 :
598 0 : if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none")
599 0 : m_outputSink << "fill: none; ";
600 0 : else if(m_style["svg:fill-rule"])
601 0 : m_outputSink << "fill-rule: " << m_style["svg:fill-rule"]->getStr().cstr() << "; ";
602 :
603 0 : if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "gradient")
604 0 : m_outputSink << "fill: url(#grad" << m_gradientIndex-1 << "); ";
605 :
606 0 : if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "bitmap")
607 0 : m_outputSink << "fill: url(#img" << m_patternIndex-1 << "); ";
608 :
609 0 : if(m_style["draw:shadow"] && m_style["draw:shadow"]->getStr() == "visible")
610 0 : m_outputSink << "filter:url(#shadow" << m_shadowIndex-1 << "); ";
611 :
612 0 : if(m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "solid")
613 0 : if (m_style["draw:fill-color"])
614 0 : m_outputSink << "fill: " << m_style["draw:fill-color"]->getStr().cstr() << "; ";
615 0 : if(m_style["draw:opacity"] && m_style["draw:opacity"]->getDouble() < 1)
616 0 : m_outputSink << "fill-opacity: " << doubleToString(m_style["draw:opacity"]->getDouble()) << "; ";
617 0 : m_outputSink << "\""; // style
618 0 : }
619 : /* vim:set shiftwidth=2 softtabstop=2 expandtab: */
|