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