1 /* libwpg\r
2 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)\r
3 * Copyright (C) 2005 Fridrich Strba (fridrich.strba@bluewin.ch)\r
4 *\r
5 * This library is free software; you can redistribute it and/or\r
6 * modify it under the terms of the GNU Library General Public\r
7 * License as published by the Free Software Foundation; either\r
8 * version 2 of the License, or (at your option) any later version.\r
9 *\r
10 * This library is distributed in the hope that it will be useful,\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
13 * Library General Public License for more details.\r
14 *\r
15 * You should have received a copy of the GNU Library General Public\r
16 * License along with this library; if not, write to the Free Software\r
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
18 *\r
19 * For further information visit http://libwpg.sourceforge.net\r
20 */\r
21 \r
22 /* "This product is not manufactured, approved, or supported by\r
23 * Corel Corporation or Corel Corporation Limited."\r
24 */\r
25 \r
26 #include <stdio.h>\r
27 \r
28 #include "libwpg/libwpg.h"\r
29 #include "libwpg/WPGStreamImplementation.h"\r
30 \r
31 using namespace libwpg;\r
32 \r
33 class InkscapePainter : public libwpg::WPGPaintInterface {\r
34 public:\r
35 InkscapePainter();\r
36 \r
37 void startDocument(double imageWidth, double imageHeight);\r
38 void endDocument();\r
39 void startLayer(unsigned int id);\r
40 void endLayer(unsigned int id);\r
41 \r
42 void setPen(const WPGPen& pen);\r
43 void setBrush(const WPGBrush& brush);\r
44 void setFillRule(FillRule rule);\r
45 \r
46 void drawRectangle(const WPGRect& rect, double rx, double ry);\r
47 void drawEllipse(const WPGPoint& center, double rx, double ry);\r
48 void drawPolygon(const WPGPointArray& vertices);\r
49 void drawPath(const WPGPath& path);\r
50 \r
51 private:\r
52 WPGPen m_pen;\r
53 WPGBrush m_brush;\r
54 FillRule m_fillRule;\r
55 int m_gradientIndex;\r
56 void writeStyle();\r
57 };\r
58 \r
59 InkscapePainter::InkscapePainter(): m_fillRule(AlternatingFill), m_gradientIndex(1)\r
60 {\r
61 }\r
62 \r
63 void InkscapePainter::startDocument(double width, double height) \r
64 {\r
65 printf("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");\r
66 printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"");\r
67 printf(" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");\r
68 \r
69 printf("<!-- Created with wpg2svg/libwpg %s -->\n", LIBWPG_VERSION_STRING);\r
70 \r
71 printf("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" ");\r
72 printf("xmlns:xlink=\"http://www.w3.org/1999/xlink\" "); \r
73 printf("width=\"%g\" height=\"%f\" >\n", 72*width, 72*height);\r
74 \r
75 m_gradientIndex = 1;\r
76 }\r
77 \r
78 void InkscapePainter::endDocument()\r
79 {\r
80 printf("</svg>\n");\r
81 }\r
82 \r
83 void InkscapePainter::setPen(const WPGPen& pen)\r
84 {\r
85 m_pen = pen;\r
86 }\r
87 \r
88 void InkscapePainter::setBrush(const WPGBrush& brush)\r
89 {\r
90 m_brush = brush;\r
91 \r
92 if(m_brush.style == WPGBrush::Gradient)\r
93 {\r
94 double angle = m_brush.gradient.angle();\r
95 \r
96 printf("<defs>\n");\r
97 printf(" <linearGradient id=\"grad%d\" >\n", m_gradientIndex++);\r
98 for(unsigned c = 0; c < m_brush.gradient.count(); c++)\r
99 {\r
100 // round to nearest percentage\r
101 int ofs = (int)(100.0*m_brush.gradient.stopOffset(c)+0.5);\r
102 \r
103 WPGColor color = m_brush.gradient.stopColor(c);\r
104 printf(" <stop offset=\"%d%%\" stop-color=\"#%02x%02x%02x\" />\n",\r
105 ofs, color.red, color.green, color.blue);\r
106 }\r
107 printf(" </linearGradient>\n");\r
108 \r
109 // not a simple horizontal gradient\r
110 if(angle != -90.0)\r
111 {\r
112 printf(" <linearGradient xlink:href=\"#grad%d\"", m_gradientIndex-1);\r
113 printf(" id=\"grad%d\" ", m_gradientIndex++);\r
114 printf("x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\" "); \r
115 printf("gradientTransform=\"rotate(%f)\" ", angle);\r
116 printf("gradientUnits=\"objectBoundingBox\" >\n");\r
117 printf(" </linearGradient>\n");\r
118 }\r
119 \r
120 printf("</defs>\n");\r
121 }\r
122 }\r
123 \r
124 void InkscapePainter::setFillRule(FillRule rule)\r
125 {\r
126 m_fillRule = rule;\r
127 }\r
128 \r
129 void InkscapePainter::startLayer(unsigned int id)\r
130 {\r
131 printf("<g id=\"Layer%d\" >\n", id);\r
132 }\r
133 \r
134 void InkscapePainter::endLayer(unsigned int)\r
135 {\r
136 printf("</g>\n");\r
137 }\r
138 \r
139 void InkscapePainter::drawRectangle(const WPGRect& rect, double rx, double ry)\r
140 {\r
141 printf("<rect ");\r
142 printf("x=\"%f\" y=\"%f\" ", 72*rect.x1, 72*rect.y1);\r
143 printf("width=\"%f\" height=\"%f\" ", 72*rect.width(), 72*rect.height());\r
144 if((rx !=0) || (ry !=0))\r
145 printf("rx=\"%f\" ry=\"%f\" ", 72*rx, 72*ry);\r
146 writeStyle();\r
147 printf("/>\n");\r
148 }\r
149 \r
150 void InkscapePainter::drawEllipse(const WPGPoint& center, double rx, double ry)\r
151 {\r
152 printf("<ellipse ");\r
153 printf("cx=\"%f\" cy=\"%f\" ", 72*center.x, 72*center.y);\r
154 printf("rx=\"%f\" ry=\"%f\" ", 72*rx, 72*ry);\r
155 writeStyle();\r
156 printf("/>\n");\r
157 }\r
158 \r
159 void InkscapePainter::drawPolygon(const WPGPointArray& vertices)\r
160 {\r
161 if(vertices.count() < 2)\r
162 return;\r
163 \r
164 if(vertices.count() == 2)\r
165 {\r
166 const WPGPoint& p1 = vertices[0];\r
167 const WPGPoint& p2 = vertices[1];\r
168 printf("<line ");\r
169 printf("x1=\"%f\" y1=\"%f\" ", 72*p1.x, 72*p1.y);\r
170 printf("x2=\"%f\" y2=\"%f\"\n", 72*p2.x, 72*p2.y);\r
171 writeStyle();\r
172 printf("/>\n");\r
173 }\r
174 else\r
175 {\r
176 printf("<polyline ");\r
177 printf("points=\"");\r
178 for(unsigned i = 0; i < vertices.count(); i++)\r
179 {\r
180 printf("%f %f", 72*vertices[i].x, 72*vertices[i].y);\r
181 if(i < vertices.count()-1) printf(", ");\r
182 }\r
183 printf("\"\n");\r
184 writeStyle();\r
185 printf("/>\n");\r
186 }\r
187 }\r
188 \r
189 void InkscapePainter::drawPath(const WPGPath& path)\r
190 {\r
191 printf("<path d=\"");\r
192 for(unsigned i = 0; i < path.count(); i++)\r
193 {\r
194 WPGPathElement element = path.element(i);\r
195 WPGPoint point = element.point;\r
196 switch(element.type)\r
197 {\r
198 case WPGPathElement::MoveToElement:\r
199 printf("\n M%f,%f ", 72*point.x, 72*point.y );\r
200 break;\r
201 \r
202 case WPGPathElement::LineToElement:\r
203 printf("\n L%f,%f ", 72*point.x, 72*point.y );\r
204 break;\r
205 \r
206 case WPGPathElement::CurveToElement:\r
207 printf("C");\r
208 printf("%f,%f ", 72*element.extra1.x, 72*element.extra1.y );\r
209 printf("%f,%f ", 72*element.extra2.x, 72*element.extra2.y );\r
210 printf("%f,%f", 72*point.x, 72*point.y );\r
211 break;\r
212 \r
213 default:\r
214 break;\r
215 }\r
216 }\r
217 printf("\" \n");\r
218 writeStyle();\r
219 printf("/>\n");\r
220 }\r
221 \r
222 // create "style" attribute based on current pen and brush\r
223 void InkscapePainter::writeStyle()\r
224 {\r
225 printf("style=\"");\r
226 \r
227 const WPGColor& color = m_pen.foreColor;\r
228 printf("stroke-width: %f; ", 72*m_pen.width);\r
229 if(m_pen.width > 0.0)\r
230 {\r
231 printf("stroke: rgb(%d,%d,%d); ", color.red, color.green, color.blue);\r
232 if(color.alpha != 0)\r
233 // alpha = 0 means opacity = 1.0, alpha = 256 means opacity = 0\r
234 printf("stroke-opacity: %f; ", 1.0-(color.alpha/256.0));\r
235 }\r
236 \r
237 if(!m_pen.solid)\r
238 {\r
239 printf("stroke-dasharray: ");\r
240 for(unsigned i = 0; i < m_pen.dashArray.count(); i++)\r
241 {\r
242 printf("%f", 72*m_pen.dashArray.at(i)*m_pen.width);\r
243 if(i < m_pen.dashArray.count()-1) \r
244 printf(", ");\r
245 }\r
246 printf("; ");\r
247 }\r
248 \r
249 if(m_brush.style == WPGBrush::NoBrush)\r
250 printf("fill: none; ");\r
251 \r
252 if(m_fillRule == InkscapePainter::WindingFill)\r
253 printf("fill-rule: nonzero; ");\r
254 else if(m_fillRule == InkscapePainter::AlternatingFill)\r
255 printf("fill-rule: evenodd; ");\r
256 \r
257 if(m_brush.style == WPGBrush::Gradient)\r
258 printf("fill: url(#grad%d); ", m_gradientIndex-1);\r
259 \r
260 if(m_brush.style == WPGBrush::Solid)\r
261 printf("fill: rgb(%d,%d,%d); ", m_brush.foreColor.red, \r
262 m_brush.foreColor.green, m_brush.foreColor.blue);\r
263 \r
264 printf("\""); // style\r
265 }\r
266 \r
267 \r
268 int main(int argc, char *argv[])\r
269 {\r
270 if (argc < 2)\r
271 {\r
272 printf("usage: wpg2svg <WordPerfect Graphic>\n");\r
273 return -1;\r
274 }\r
275 \r
276 const char* filename = argv[1];\r
277 WPGInputStream* input = new WPGFileStream(filename);\r
278 if (input->isOle())\r
279 {\r
280 WPGInputStream* olestream = input->getWPGOleStream();\r
281 if (olestream)\r
282 {\r
283 delete input;\r
284 input = olestream;\r
285 }\r
286 }\r
287 \r
288 if (!WPGraphics::isSupported(input))\r
289 {\r
290 fprintf(stderr, "ERROR: Unsupported file format (unsupported version) or file is encrypted!\n");\r
291 return 1;\r
292 }\r
293 \r
294 InkscapePainter painter;\r
295 WPGraphics::parse(input, &painter);\r
296 \r
297 return 0;\r
298 }\r