/src/libcdr/src/lib/CDRContentCollector.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* |
3 | | * This file is part of the libcdr project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | */ |
9 | | |
10 | | #include "CDRContentCollector.h" |
11 | | |
12 | | #include <math.h> |
13 | | #include <string.h> |
14 | | #include <librevenge/librevenge.h> |
15 | | #include <libcdr/libcdr.h> |
16 | | #include "CDROutputElementList.h" |
17 | | #include "libcdr_utils.h" |
18 | | |
19 | | #ifndef DUMP_PATTERN |
20 | | #define DUMP_PATTERN 0 |
21 | | #endif |
22 | | |
23 | | #ifndef DUMP_VECT |
24 | | #define DUMP_VECT 0 |
25 | | #endif |
26 | | |
27 | | namespace libcdr |
28 | | { |
29 | | namespace |
30 | | { |
31 | | |
32 | | /// Move the number into [0;1] range. |
33 | | void normalize(double &d) |
34 | 0 | { |
35 | 0 | if (d < 0.0) |
36 | 0 | { |
37 | 0 | const double n = d + static_cast<unsigned long>(-d) + 1.0; |
38 | 0 | if ((n < 0.0) || (n > 1.0)) |
39 | 0 | d = 0.0; // The number was too big, thus rounded. Just pick a value. |
40 | 0 | else |
41 | 0 | d = n; |
42 | 0 | } |
43 | 0 | if (d > 1.0) |
44 | 0 | { |
45 | 0 | const double n = d - static_cast<unsigned long>(d); |
46 | 0 | if ((n < 0.0) || (n > 1.0)) |
47 | 0 | d = 0.0; // The number was too big, thus rounded. Just pick a value. |
48 | 0 | else |
49 | 0 | d = n; |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | void normalizeAngle(double &angle) |
54 | 43.4k | { |
55 | 43.4k | angle = fmod(angle, 360); |
56 | 43.4k | if (angle < 0) |
57 | 1.07k | angle += 360; |
58 | 43.4k | } |
59 | | |
60 | | } |
61 | | } |
62 | | |
63 | | libcdr::CDRContentCollector::CDRContentCollector(libcdr::CDRParserState &ps, librevenge::RVNGDrawingInterface *painter, |
64 | | bool reverseOrder) |
65 | 8.19k | : m_painter(painter), m_isDocumentStarted(false), m_isPageProperties(false), m_isPageStarted(false), |
66 | 8.19k | m_ignorePage(false), m_page(ps.m_pages[0]), m_pageIndex(0), m_currentFillStyle(), m_currentLineStyle(), |
67 | 8.19k | m_spnd(0), m_currentObjectLevel(0), m_currentGroupLevel(0), m_currentVectLevel(0), m_currentPageLevel(0), |
68 | 8.19k | m_currentStyleId(0), m_currentImage(), m_currentText(nullptr), m_currentBBox(), m_currentTextBox(), m_currentPath(), |
69 | 8.19k | m_currentTransforms(), m_fillTransforms(), m_polygon(), m_isInPolygon(false), m_isInSpline(false), |
70 | 8.19k | m_outputElementsStack(nullptr), m_contentOutputElementsStack(), m_fillOutputElementsStack(), |
71 | 8.19k | m_outputElementsQueue(nullptr), m_contentOutputElementsQueue(), m_fillOutputElementsQueue(), |
72 | 8.19k | m_groupLevels(), m_groupTransforms(), m_splineData(), m_fillOpacity(1.0), m_reverseOrder(reverseOrder), |
73 | 8.19k | m_ps(ps) |
74 | 8.19k | { |
75 | 8.19k | m_outputElementsStack = &m_contentOutputElementsStack; |
76 | 8.19k | m_outputElementsQueue = &m_contentOutputElementsQueue; |
77 | 8.19k | } |
78 | | |
79 | | libcdr::CDRContentCollector::~CDRContentCollector() |
80 | 8.19k | { |
81 | 8.19k | if (m_isPageStarted) |
82 | 0 | _endPage(); |
83 | 8.19k | if (m_isDocumentStarted) |
84 | 714 | _endDocument(); |
85 | 8.19k | } |
86 | | |
87 | | void libcdr::CDRContentCollector::_startDocument() |
88 | 714 | { |
89 | 714 | if (m_isDocumentStarted) |
90 | 0 | return; |
91 | 714 | librevenge::RVNGPropertyList propList; |
92 | 714 | if (m_painter) |
93 | 714 | m_painter->startDocument(propList); |
94 | 714 | m_isDocumentStarted = true; |
95 | 714 | } |
96 | | |
97 | | void libcdr::CDRContentCollector::_endDocument() |
98 | 714 | { |
99 | 714 | if (!m_isDocumentStarted) |
100 | 0 | return; |
101 | 714 | if (m_isPageStarted) |
102 | 0 | _endPage(); |
103 | 714 | if (m_painter) |
104 | 714 | m_painter->endDocument(); |
105 | 714 | m_isDocumentStarted = false; |
106 | 714 | } |
107 | | |
108 | | void libcdr::CDRContentCollector::_startPage(double width, double height) |
109 | 4.00k | { |
110 | 4.00k | if (m_ignorePage) |
111 | 0 | return; |
112 | 4.00k | if (!m_isDocumentStarted) |
113 | 714 | _startDocument(); |
114 | 4.00k | librevenge::RVNGPropertyList propList; |
115 | 4.00k | propList.insert("svg:width", width); |
116 | 4.00k | propList.insert("svg:height", height); |
117 | 4.00k | if (m_painter) |
118 | 4.00k | m_painter->startPage(propList); |
119 | 4.00k | m_isPageStarted = true; |
120 | 4.00k | } |
121 | | |
122 | | void libcdr::CDRContentCollector::_endPage() |
123 | 513k | { |
124 | 513k | if (!m_isPageStarted) |
125 | 509k | return; |
126 | 23.5k | while (!m_contentOutputElementsStack.empty()) |
127 | 19.5k | { |
128 | 19.5k | m_contentOutputElementsStack.top().draw(m_painter); |
129 | 19.5k | m_contentOutputElementsStack.pop(); |
130 | 19.5k | } |
131 | 4.00k | while (!m_contentOutputElementsQueue.empty()) |
132 | 0 | { |
133 | 0 | m_contentOutputElementsQueue.front().draw(m_painter); |
134 | 0 | m_contentOutputElementsQueue.pop(); |
135 | 0 | } |
136 | 4.00k | if (m_painter) |
137 | 4.00k | m_painter->endPage(); |
138 | 4.00k | m_isPageStarted = false; |
139 | 4.00k | } |
140 | | |
141 | | void libcdr::CDRContentCollector::collectPage(unsigned level) |
142 | 26.4k | { |
143 | 26.4k | m_isPageProperties = true; |
144 | 26.4k | m_ignorePage = false; |
145 | 26.4k | m_currentPageLevel = level; |
146 | 26.4k | m_page = m_ps.m_pages[m_pageIndex++]; |
147 | | |
148 | 26.4k | } |
149 | | |
150 | | void libcdr::CDRContentCollector::collectObject(unsigned level) |
151 | 9.42k | { |
152 | 9.42k | if (!m_isPageStarted && !m_currentVectLevel && !m_ignorePage) |
153 | 2.12k | _startPage(m_page.width, m_page.height); |
154 | 9.42k | m_currentObjectLevel = level; |
155 | 9.42k | m_currentFillStyle = CDRFillStyle(); |
156 | 9.42k | m_currentLineStyle = CDRLineStyle(); |
157 | 9.42k | m_currentStyleId = 0; |
158 | 9.42k | m_currentBBox = CDRBox(); |
159 | 9.42k | } |
160 | | |
161 | | void libcdr::CDRContentCollector::collectGroup(unsigned level) |
162 | 2.62k | { |
163 | 2.62k | if (!m_isPageStarted && !m_currentVectLevel && !m_ignorePage) |
164 | 1.52k | _startPage(m_page.width, m_page.height); |
165 | 2.62k | CDROutputElementList outputElement; |
166 | 2.62k | if (m_reverseOrder) |
167 | 2.62k | { |
168 | | // Since the CDR objects are drawn in reverse order, reverse the logic of groups too |
169 | 2.62k | outputElement.addEndGroup(); |
170 | 2.62k | m_outputElementsStack->push(outputElement); |
171 | 2.62k | } |
172 | 0 | else |
173 | 0 | { |
174 | 0 | librevenge::RVNGPropertyList propList; |
175 | 0 | outputElement.addStartGroup(propList); |
176 | 0 | m_outputElementsQueue->push(outputElement); |
177 | 0 | } |
178 | 2.62k | m_groupLevels.push(level); |
179 | 2.62k | m_groupTransforms.push(CDRTransforms()); |
180 | 2.62k | } |
181 | | |
182 | | void libcdr::CDRContentCollector::collectVect(unsigned level) |
183 | 339 | { |
184 | 339 | m_currentVectLevel = level; |
185 | 339 | m_outputElementsStack = &m_fillOutputElementsStack; |
186 | 339 | m_outputElementsQueue = &m_fillOutputElementsQueue; |
187 | 339 | m_page.width = 0.0; |
188 | 339 | m_page.height = 0.0; |
189 | 339 | m_page.offsetX = 0.0; |
190 | 339 | m_page.offsetY = 0.0; |
191 | 339 | } |
192 | | |
193 | | void libcdr::CDRContentCollector::collectFlags(unsigned flags, bool considerFlags) |
194 | 9.63k | { |
195 | 9.63k | if (m_isPageProperties && !(flags & 0x00ff0000)) |
196 | 427 | { |
197 | 427 | if (!m_isPageStarted) |
198 | 359 | _startPage(m_page.width, m_page.height); |
199 | 427 | } |
200 | 9.20k | else if (m_isPageProperties && considerFlags) |
201 | 400 | m_ignorePage = true; |
202 | 9.63k | m_isPageProperties = false; |
203 | 9.63k | } |
204 | | |
205 | | void libcdr::CDRContentCollector::collectOtherList() |
206 | 139k | { |
207 | | // m_isPageProperties = false; |
208 | 139k | } |
209 | | |
210 | | void libcdr::CDRContentCollector::collectPath(const CDRPath &path) |
211 | 82.0k | { |
212 | 82.0k | CDR_DEBUG_MSG(("CDRContentCollector::collectPath\n")); |
213 | 82.0k | m_currentPath.appendPath(path); |
214 | 82.0k | } |
215 | | |
216 | | void libcdr::CDRContentCollector::_flushCurrentPath() |
217 | 519k | { |
218 | 519k | CDR_DEBUG_MSG(("CDRContentCollector::_flushCurrentPath\n")); |
219 | 519k | CDROutputElementList outputElement; |
220 | 519k | if (!m_currentPath.empty() || (!m_splineData.empty() && m_isInSpline)) |
221 | 66.6k | { |
222 | 66.6k | if (m_polygon && m_isInPolygon) |
223 | 73 | m_polygon->create(m_currentPath); |
224 | 66.6k | m_polygon.reset(); |
225 | 66.6k | m_isInPolygon = false; |
226 | 66.6k | if (!m_splineData.empty() && m_isInSpline) |
227 | 202 | m_splineData.create(m_currentPath); |
228 | 66.6k | m_splineData.clear(); |
229 | 66.6k | m_isInSpline = false; |
230 | 66.6k | bool firstPoint = true; |
231 | 66.6k | bool wasMove = false; |
232 | 66.6k | double initialX = 0.0; |
233 | 66.6k | double initialY = 0.0; |
234 | 66.6k | double previousX = 0.0; |
235 | 66.6k | double previousY = 0.0; |
236 | 66.6k | double x = 0.0; |
237 | 66.6k | double y = 0.0; |
238 | 66.6k | librevenge::RVNGPropertyList style; |
239 | 66.6k | _fillProperties(style); |
240 | 66.6k | _lineProperties(style); |
241 | 66.6k | outputElement.addStyle(style); |
242 | 66.6k | m_currentPath.transform(m_currentTransforms); |
243 | 66.6k | if (!m_groupTransforms.empty()) |
244 | 353 | m_currentPath.transform(m_groupTransforms.top()); |
245 | 66.6k | CDRTransform tmpTrafo(1.0, 0.0, -m_page.offsetX, 0.0, 1.0, -m_page.offsetY); |
246 | 66.6k | m_currentPath.transform(tmpTrafo); |
247 | 66.6k | tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, m_page.height); |
248 | 66.6k | m_currentPath.transform(tmpTrafo); |
249 | | |
250 | 66.6k | std::vector<librevenge::RVNGPropertyList> tmpPath; |
251 | | |
252 | 66.6k | librevenge::RVNGPropertyListVector path; |
253 | 66.6k | m_currentPath.writeOut(path); |
254 | | |
255 | 66.6k | bool isPathClosed = m_currentPath.isClosed(); |
256 | | |
257 | 66.6k | librevenge::RVNGPropertyListVector::Iter i(path); |
258 | 2.24M | for (i.rewind(); i.next();) |
259 | 2.17M | { |
260 | 2.17M | if (!i()["librevenge:path-action"]) |
261 | 0 | continue; |
262 | 2.17M | if (i()["svg:x"] && i()["svg:y"]) |
263 | 1.93M | { |
264 | 1.93M | bool ignoreM = false; |
265 | 1.93M | x = i()["svg:x"]->getDouble(); |
266 | 1.93M | y = i()["svg:y"]->getDouble(); |
267 | 1.93M | if (firstPoint) |
268 | 66.6k | { |
269 | 66.6k | initialX = x; |
270 | 66.6k | initialY = y; |
271 | 66.6k | firstPoint = false; |
272 | 66.6k | wasMove = true; |
273 | 66.6k | } |
274 | 1.86M | else if (i()["librevenge:path-action"]->getStr() == "M") |
275 | 1.39M | { |
276 | | // This is needed for a good generation of path from polygon |
277 | 1.39M | if (CDR_ALMOST_ZERO(previousX - x) && CDR_ALMOST_ZERO(previousY - y)) |
278 | 364k | ignoreM = true; |
279 | 1.03M | else |
280 | 1.03M | { |
281 | 1.03M | if (!tmpPath.empty()) |
282 | 1.03M | { |
283 | 1.03M | if (!wasMove) |
284 | 101k | { |
285 | 101k | if ((CDR_ALMOST_ZERO(initialX - previousX) && CDR_ALMOST_ZERO(initialY - previousY)) || isPathClosed) |
286 | 27.5k | { |
287 | 27.5k | librevenge::RVNGPropertyList node; |
288 | 27.5k | node.insert("librevenge:path-action", "Z"); |
289 | 27.5k | tmpPath.push_back(node); |
290 | 27.5k | } |
291 | 101k | } |
292 | 931k | else |
293 | 931k | tmpPath.pop_back(); |
294 | 1.03M | } |
295 | 1.03M | } |
296 | | |
297 | 1.39M | if (!ignoreM) |
298 | 1.03M | { |
299 | 1.03M | initialX = x; |
300 | 1.03M | initialY = y; |
301 | 1.03M | wasMove = true; |
302 | 1.03M | } |
303 | | |
304 | 1.39M | } |
305 | 466k | else |
306 | 466k | wasMove = false; |
307 | | |
308 | 1.93M | if (!ignoreM) |
309 | 1.56M | { |
310 | 1.56M | tmpPath.push_back(i()); |
311 | 1.56M | previousX = x; |
312 | 1.56M | previousY = y; |
313 | 1.56M | } |
314 | | |
315 | 1.93M | } |
316 | 247k | else if (i()["librevenge:path-action"]->getStr() == "Z") |
317 | 247k | { |
318 | 247k | if (!tmpPath.empty() && tmpPath.back()["librevenge:path-action"] && tmpPath.back()["librevenge:path-action"]->getStr() != "Z") |
319 | 228k | tmpPath.push_back(i()); |
320 | 247k | } |
321 | 2.17M | } |
322 | 66.6k | if (!tmpPath.empty()) |
323 | 66.6k | { |
324 | 66.6k | if (!wasMove) |
325 | 22.6k | { |
326 | 22.6k | if ((CDR_ALMOST_ZERO(initialX - previousX) && CDR_ALMOST_ZERO(initialY - previousY)) || isPathClosed) |
327 | 19.3k | { |
328 | 19.3k | if (tmpPath.back()["librevenge:path-action"] && tmpPath.back()["librevenge:path-action"]->getStr() != "Z") |
329 | 7.83k | { |
330 | 7.83k | librevenge::RVNGPropertyList closedPath; |
331 | 7.83k | closedPath.insert("librevenge:path-action", "Z"); |
332 | 7.83k | tmpPath.push_back(closedPath); |
333 | 7.83k | } |
334 | 19.3k | } |
335 | 22.6k | } |
336 | 43.9k | else |
337 | 43.9k | tmpPath.pop_back(); |
338 | 66.6k | } |
339 | 66.6k | if (!tmpPath.empty()) |
340 | 25.6k | { |
341 | 25.6k | librevenge::RVNGPropertyListVector outputPath; |
342 | 880k | for (std::vector<librevenge::RVNGPropertyList>::const_iterator iter = tmpPath.begin(); iter != tmpPath.end(); ++iter) |
343 | 855k | outputPath.append(*iter); |
344 | 25.6k | librevenge::RVNGPropertyList propList; |
345 | 25.6k | propList.insert("svg:d", outputPath); |
346 | 25.6k | outputElement.addPath(propList); |
347 | | |
348 | 25.6k | } |
349 | 66.6k | m_currentPath.clear(); |
350 | 66.6k | } |
351 | | |
352 | 519k | if (m_currentImage.getImage().size()) |
353 | 4.73k | { |
354 | 4.73k | double cx = m_currentImage.getMiddleX(); |
355 | 4.73k | double cy = m_currentImage.getMiddleY(); |
356 | 4.73k | double corner1x = m_currentImage.m_x1; |
357 | 4.73k | double corner1y = m_currentImage.m_y1; |
358 | 4.73k | double corner2x = m_currentImage.m_x1; |
359 | 4.73k | double corner2y = m_currentImage.m_y2; |
360 | 4.73k | double corner3x = m_currentImage.m_x2; |
361 | 4.73k | double corner3y = m_currentImage.m_y2; |
362 | 4.73k | m_currentTransforms.applyToPoint(cx, cy); |
363 | 4.73k | m_currentTransforms.applyToPoint(corner1x, corner1y); |
364 | 4.73k | m_currentTransforms.applyToPoint(corner2x, corner2y); |
365 | 4.73k | m_currentTransforms.applyToPoint(corner3x, corner3y); |
366 | 4.73k | if (!m_groupTransforms.empty()) |
367 | 14 | { |
368 | 14 | m_groupTransforms.top().applyToPoint(cx, cy); |
369 | 14 | m_groupTransforms.top().applyToPoint(corner1x, corner1y); |
370 | 14 | m_groupTransforms.top().applyToPoint(corner2x, corner2y); |
371 | 14 | m_groupTransforms.top().applyToPoint(corner3x, corner3y); |
372 | 14 | } |
373 | 4.73k | CDRTransform tmpTrafo(1.0, 0.0, -m_page.offsetX, 0.0, 1.0, -m_page.offsetY); |
374 | 4.73k | tmpTrafo.applyToPoint(cx, cy); |
375 | 4.73k | tmpTrafo.applyToPoint(corner1x, corner1y); |
376 | 4.73k | tmpTrafo.applyToPoint(corner2x, corner2y); |
377 | 4.73k | tmpTrafo.applyToPoint(corner3x, corner3y); |
378 | 4.73k | tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, m_page.height); |
379 | 4.73k | tmpTrafo.applyToPoint(cx, cy); |
380 | 4.73k | tmpTrafo.applyToPoint(corner1x, corner1y); |
381 | 4.73k | tmpTrafo.applyToPoint(corner2x, corner2y); |
382 | 4.73k | tmpTrafo.applyToPoint(corner3x, corner3y); |
383 | 4.73k | bool flipX(m_currentTransforms.getFlipX()); |
384 | 4.73k | bool flipY(m_currentTransforms.getFlipY()); |
385 | 4.73k | double width = sqrt((corner2x - corner3x)*(corner2x - corner3x) + (corner2y - corner3y)*(corner2y - corner3y)); |
386 | 4.73k | double height = sqrt((corner2x - corner1x)*(corner2x - corner1x) + (corner2y - corner1y)*(corner2y - corner1y)); |
387 | 4.73k | double rotate = atan2(corner3y-corner2y, corner3x-corner2x); |
388 | | |
389 | 4.73k | librevenge::RVNGPropertyList propList; |
390 | | |
391 | 4.73k | propList.insert("svg:x", cx - width / 2.0); |
392 | 4.73k | propList.insert("svg:width", width); |
393 | 4.73k | propList.insert("svg:y", cy - height / 2.0); |
394 | 4.73k | propList.insert("svg:height", height); |
395 | | |
396 | 4.73k | if (flipX) |
397 | 0 | { |
398 | 0 | propList.insert("draw:mirror-horizontal", true); |
399 | 0 | rotate = M_PI - rotate; |
400 | 0 | } |
401 | 4.73k | if (flipY) |
402 | 0 | { |
403 | 0 | propList.insert("draw:mirror-vertical", true); |
404 | 0 | rotate *= -1.0; |
405 | 0 | } |
406 | | |
407 | 4.73k | while (rotate < 0.0) |
408 | 1 | rotate += 2.0*M_PI; |
409 | 4.73k | while (rotate > 2.0*M_PI) |
410 | 0 | rotate -= 2.0*M_PI; |
411 | | |
412 | 4.73k | if (!CDR_ALMOST_ZERO(rotate)) |
413 | 1.04k | propList.insert("librevenge:rotate", rotate * 180 / M_PI, librevenge::RVNG_GENERIC); |
414 | | |
415 | 4.73k | propList.insert("librevenge:mime-type", "image/bmp"); |
416 | 4.73k | propList.insert("office:binary-data", m_currentImage.getImage()); |
417 | 4.73k | outputElement.addGraphicObject(propList); |
418 | 4.73k | } |
419 | 519k | if (m_currentText && !m_currentText->empty()) |
420 | 5.04k | { |
421 | 5.04k | double x1 = m_currentTextBox.m_x; |
422 | 5.04k | double y1 = m_currentTextBox.m_y; |
423 | 5.04k | double x2 = m_currentTextBox.m_x + m_currentTextBox.m_w; |
424 | 5.04k | double y2 = m_currentTextBox.m_y - m_currentTextBox.m_h; |
425 | 5.04k | if (!CDR_ALMOST_ZERO(m_currentTextBox.m_h) && !CDR_ALMOST_ZERO(m_currentTextBox.m_w)) |
426 | 293 | { |
427 | 293 | m_currentTransforms.applyToPoint(x1, y1); |
428 | 293 | m_currentTransforms.applyToPoint(x2, y2); |
429 | 293 | if (!m_groupTransforms.empty()) |
430 | 3 | { |
431 | 3 | m_groupTransforms.top().applyToPoint(x1, y1); |
432 | 3 | m_groupTransforms.top().applyToPoint(x2, y2); |
433 | 3 | } |
434 | 293 | } |
435 | 4.74k | else if (!CDR_ALMOST_ZERO(m_currentBBox.getWidth()) && !CDR_ALMOST_ZERO(m_currentBBox.getHeight())) |
436 | 2.30k | { |
437 | 2.30k | y1 = m_currentBBox.getMinY(); |
438 | 2.30k | y2 = m_currentBBox.getMinY() + m_currentBBox.getHeight(); |
439 | 2.30k | if ((*m_currentText)[0].m_line[0].m_style.m_align == 2) // Center |
440 | 1.26k | { |
441 | 1.26k | x1 = m_currentBBox.getMinX() - m_currentBBox.getWidth() / 4.0; |
442 | 1.26k | x2 = m_currentBBox.getMinX() + (3.0 * m_currentBBox.getWidth() / 4.0); |
443 | 1.26k | } |
444 | 1.04k | else if ((*m_currentText)[0].m_line[0].m_style.m_align == 3) // Right |
445 | 117 | { |
446 | 117 | x1 = m_currentBBox.getMinX() - m_currentBBox.getWidth() / 2.0; |
447 | 117 | x2 = m_currentBBox.getMinX() + m_currentBBox.getWidth() / 2.0; |
448 | 117 | } |
449 | 927 | else |
450 | 927 | { |
451 | 927 | x1 = m_currentBBox.getMinX(); |
452 | 927 | x2 = m_currentBBox.getMinX() + m_currentBBox.getWidth(); |
453 | 927 | } |
454 | 2.30k | } |
455 | 2.44k | else if (!m_currentTransforms.empty()) |
456 | 46 | { |
457 | 46 | x1 = m_currentTransforms.getTranslateX(); |
458 | 46 | y1 = m_currentTransforms.getTranslateY(); |
459 | 46 | x2 = x1; |
460 | 46 | y2 = y1; |
461 | 46 | } |
462 | | |
463 | 5.04k | CDRTransform tmpTrafo(1.0, 0.0, -m_page.offsetX, 0.0, 1.0, -m_page.offsetY); |
464 | 5.04k | tmpTrafo.applyToPoint(x1, y1); |
465 | 5.04k | tmpTrafo.applyToPoint(x2, y2); |
466 | 5.04k | tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, m_page.height); |
467 | 5.04k | tmpTrafo.applyToPoint(x1, y1); |
468 | 5.04k | tmpTrafo.applyToPoint(x2, y2); |
469 | 5.04k | if (x1 > x2) |
470 | 88 | std::swap(x1, x2); |
471 | 5.04k | if (y1 > y2) |
472 | 2.45k | std::swap(y1, y2); |
473 | | |
474 | 5.04k | librevenge::RVNGPropertyList textFrameProps; |
475 | 5.04k | textFrameProps.insert("svg:width", fabs(x2-x1)); |
476 | 5.04k | textFrameProps.insert("svg:height", fabs(y2-y1)); |
477 | 5.04k | textFrameProps.insert("svg:x", x1); |
478 | 5.04k | textFrameProps.insert("svg:y", y1); |
479 | 5.04k | textFrameProps.insert("fo:padding-top", 0.0); |
480 | 5.04k | textFrameProps.insert("fo:padding-bottom", 0.0); |
481 | 5.04k | textFrameProps.insert("fo:padding-left", 0.0); |
482 | 5.04k | textFrameProps.insert("fo:padding-right", 0.0); |
483 | 5.04k | outputElement.addStartTextObject(textFrameProps); |
484 | 5.04k | for (const auto &i : *m_currentText) |
485 | 11.4k | { |
486 | 11.4k | const std::vector<CDRText> ¤tLine = i.m_line; |
487 | 11.4k | if (currentLine.empty()) |
488 | 0 | continue; |
489 | 11.4k | librevenge::RVNGPropertyList paraProps; |
490 | 11.4k | bool rtl = false; |
491 | 11.4k | switch (currentLine[0].m_style.m_align) |
492 | 11.4k | { |
493 | 614 | case 1: // Left |
494 | 614 | if (!rtl) |
495 | 614 | paraProps.insert("fo:text-align", "left"); |
496 | 0 | else |
497 | 0 | paraProps.insert("fo:text-align", "end"); |
498 | 614 | break; |
499 | 2.06k | case 2: // Center |
500 | 2.06k | paraProps.insert("fo:text-align", "center"); |
501 | 2.06k | break; |
502 | 117 | case 3: // Right |
503 | 117 | if (!rtl) |
504 | 117 | paraProps.insert("fo:text-align", "end"); |
505 | 0 | else |
506 | 0 | paraProps.insert("fo:text-align", "left"); |
507 | 117 | break; |
508 | 1 | case 4: // Full justify |
509 | 1 | paraProps.insert("fo:text-align", "justify"); |
510 | 1 | break; |
511 | 1 | case 5: // Force justify |
512 | 1 | paraProps.insert("fo:text-align", "full"); |
513 | 1 | break; |
514 | 8.66k | case 0: // None |
515 | 8.66k | default: |
516 | 8.66k | break; |
517 | 11.4k | } |
518 | 11.4k | outputElement.addOpenParagraph(paraProps); |
519 | 11.4k | for (const auto &j : currentLine) |
520 | 3.93M | { |
521 | 3.93M | if (!j.m_text.empty()) |
522 | 1.84M | { |
523 | 1.84M | librevenge::RVNGPropertyList spanProps; |
524 | 1.84M | double fontSize = (double)cdr_round(144.0*j.m_style.m_fontSize) / 2.0; |
525 | 1.84M | spanProps.insert("fo:font-size", fontSize, librevenge::RVNG_POINT); |
526 | 1.84M | if (j.m_style.m_fontName.len()) |
527 | 65.2k | spanProps.insert("style:font-name", j.m_style.m_fontName); |
528 | 1.84M | if (j.m_style.m_fillStyle.fillType != (unsigned short)-1) |
529 | 11.4k | spanProps.insert("fo:color", m_ps.getRGBColorString(j.m_style.m_fillStyle.color1)); |
530 | 1.84M | outputElement.addOpenSpan(spanProps); |
531 | 1.84M | outputElement.addInsertText(j.m_text); |
532 | 1.84M | outputElement.addCloseSpan(); |
533 | 1.84M | } |
534 | 3.93M | } |
535 | 11.4k | outputElement.addCloseParagraph(); |
536 | 11.4k | } |
537 | 5.04k | outputElement.addEndTextObject(); |
538 | 5.04k | } |
539 | 519k | m_currentImage = libcdr::CDRImage(); |
540 | 519k | if (!outputElement.empty()) |
541 | 71.6k | { |
542 | 71.6k | if (m_reverseOrder) |
543 | 71.6k | m_outputElementsStack->push(outputElement); |
544 | 0 | else |
545 | 0 | m_outputElementsQueue->push(outputElement); |
546 | 71.6k | } |
547 | 519k | m_currentTransforms.clear(); |
548 | 519k | m_fillTransforms = libcdr::CDRTransforms(); |
549 | 519k | m_fillOpacity = 1.0; |
550 | 519k | m_currentText = nullptr; |
551 | 519k | } |
552 | | |
553 | | void libcdr::CDRContentCollector::collectTransform(const CDRTransforms &transforms, bool considerGroupTransform) |
554 | 11.7k | { |
555 | 11.7k | if (m_currentObjectLevel) |
556 | 6.34k | m_currentTransforms = transforms; |
557 | 5.40k | else if (!m_groupLevels.empty() && considerGroupTransform) |
558 | 486 | m_groupTransforms.top() = transforms; |
559 | 11.7k | } |
560 | | |
561 | | void libcdr::CDRContentCollector::collectFillTransform(const CDRTransforms &fillTrafos) |
562 | 3.69k | { |
563 | 3.69k | m_fillTransforms = fillTrafos; |
564 | 3.69k | } |
565 | | |
566 | | void libcdr::CDRContentCollector::collectLevel(unsigned level) |
567 | 894k | { |
568 | 894k | if (level <= m_currentObjectLevel) |
569 | 519k | { |
570 | 519k | _flushCurrentPath(); |
571 | 519k | m_currentObjectLevel = 0; |
572 | 519k | } |
573 | 896k | while (!m_groupLevels.empty() && level <= m_groupLevels.top()) |
574 | 2.62k | { |
575 | 2.62k | CDROutputElementList outputElement; |
576 | | // since the CDR objects are drawn in reverse order, reverse group marks too |
577 | 2.62k | if (m_reverseOrder) |
578 | 2.62k | { |
579 | 2.62k | librevenge::RVNGPropertyList propList; |
580 | 2.62k | outputElement.addStartGroup(propList); |
581 | 2.62k | m_outputElementsStack->push(outputElement); |
582 | 2.62k | } |
583 | 0 | else |
584 | 0 | { |
585 | 0 | outputElement.addEndGroup(); |
586 | 0 | m_outputElementsQueue->push(outputElement); |
587 | 0 | } |
588 | 2.62k | m_groupLevels.pop(); |
589 | 2.62k | m_groupTransforms.pop(); |
590 | 2.62k | } |
591 | 894k | if (m_currentVectLevel && m_spnd && m_groupLevels.empty() && (!m_fillOutputElementsStack.empty() || !m_fillOutputElementsQueue.empty())) |
592 | 125 | { |
593 | 125 | librevenge::RVNGStringVector svgOutput; |
594 | 125 | librevenge::RVNGSVGDrawingGenerator generator(svgOutput, ""); |
595 | 125 | librevenge::RVNGPropertyList propList; |
596 | 125 | propList.insert("svg:width", m_page.width); |
597 | 125 | propList.insert("svg:height", m_page.height); |
598 | 125 | generator.startPage(propList); |
599 | 1.62k | while (!m_fillOutputElementsStack.empty()) |
600 | 1.49k | { |
601 | 1.49k | m_fillOutputElementsStack.top().draw(&generator); |
602 | 1.49k | m_fillOutputElementsStack.pop(); |
603 | 1.49k | } |
604 | 125 | while (!m_fillOutputElementsQueue.empty()) |
605 | 0 | { |
606 | 0 | m_fillOutputElementsQueue.front().draw(&generator); |
607 | 0 | m_fillOutputElementsQueue.pop(); |
608 | 0 | } |
609 | | |
610 | 125 | generator.endPage(); |
611 | 125 | if (!svgOutput.empty()) |
612 | 125 | { |
613 | 125 | const char *header = |
614 | 125 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"; |
615 | 125 | librevenge::RVNGBinaryData output((const unsigned char *)header, strlen(header)); |
616 | 125 | output.append((const unsigned char *)svgOutput[0].cstr(), strlen(svgOutput[0].cstr())); |
617 | 125 | m_ps.m_vects[m_spnd] = output; |
618 | 125 | } |
619 | | #if DUMP_VECT |
620 | | librevenge::RVNGString filename; |
621 | | filename.sprintf("vect%.8x.svg", m_spnd); |
622 | | FILE *f = fopen(filename.cstr(), "wb"); |
623 | | if (f) |
624 | | { |
625 | | const unsigned char *tmpBuffer = m_ps.m_vects[m_spnd].getDataBuffer(); |
626 | | for (unsigned long k = 0; k < m_ps.m_vects[m_spnd].size(); k++) |
627 | | fprintf(f, "%c",tmpBuffer[k]); |
628 | | fclose(f); |
629 | | } |
630 | | #endif |
631 | 125 | m_spnd = 0; |
632 | 125 | m_page.width = 0.0; |
633 | 125 | m_page.height = 0.0; |
634 | 125 | m_page.offsetX = 0.0; |
635 | 125 | m_page.offsetY = 0.0; |
636 | 125 | } |
637 | 894k | if (level <= m_currentVectLevel) |
638 | 512k | { |
639 | 512k | m_currentVectLevel = 0; |
640 | 512k | m_outputElementsStack = &m_contentOutputElementsStack; |
641 | 512k | m_outputElementsQueue = &m_contentOutputElementsQueue; |
642 | 512k | m_page = m_ps.m_pages[m_pageIndex ? m_pageIndex-1 : 0]; |
643 | 512k | } |
644 | 894k | if (level <= m_currentPageLevel) |
645 | 513k | { |
646 | 513k | _endPage(); |
647 | 513k | m_currentPageLevel = 0; |
648 | 513k | } |
649 | 894k | } |
650 | | |
651 | | void libcdr::CDRContentCollector::collectFillStyleId(unsigned id) |
652 | 16.3k | { |
653 | 16.3k | std::map<unsigned, CDRFillStyle>::const_iterator iter = m_ps.m_fillStyles.find(id); |
654 | 16.3k | if (iter != m_ps.m_fillStyles.end()) |
655 | 13.2k | m_currentFillStyle = iter->second; |
656 | 16.3k | } |
657 | | |
658 | | void libcdr::CDRContentCollector::collectLineStyleId(unsigned id) |
659 | 14.6k | { |
660 | 14.6k | std::map<unsigned, CDRLineStyle>::const_iterator iter = m_ps.m_lineStyles.find(id); |
661 | 14.6k | if (iter != m_ps.m_lineStyles.end()) |
662 | 10.8k | m_currentLineStyle = iter->second; |
663 | 14.6k | } |
664 | | |
665 | | void libcdr::CDRContentCollector::collectRotate(double angle, double cx, double cy) |
666 | 0 | { |
667 | 0 | CDRTransform trafo1(1.0, 0.0, -cx, 0.0, 1.0, -cy); |
668 | 0 | m_currentPath.transform(trafo1); |
669 | 0 | CDRTransform trafo2(cos(angle), -sin(angle), 0, sin(angle), cos(angle), 0); |
670 | 0 | m_currentPath.transform(trafo2); |
671 | 0 | CDRTransform trafo3(1.0, 0.0, cx, 0.0, 1.0, cy); |
672 | 0 | m_currentPath.transform(trafo3); |
673 | 0 | } |
674 | | |
675 | | void libcdr::CDRContentCollector::collectPolygon() |
676 | 368 | { |
677 | 368 | m_isInPolygon = true; |
678 | 368 | } |
679 | | |
680 | | void libcdr::CDRContentCollector::collectSpline() |
681 | 362 | { |
682 | 362 | m_isInSpline = true; |
683 | 362 | } |
684 | | |
685 | | void libcdr::CDRContentCollector::collectPolygonTransform(unsigned numAngles, unsigned nextPoint, double rx, double ry, double cx, double cy) |
686 | 2.05k | { |
687 | 2.05k | m_polygon.reset(new CDRPolygon(numAngles, nextPoint, rx, ry, cx, cy)); |
688 | 2.05k | } |
689 | | |
690 | | void libcdr::CDRContentCollector::_fillProperties(librevenge::RVNGPropertyList &propList) |
691 | 66.6k | { |
692 | 66.6k | if (m_currentFillStyle.fillType == (unsigned short)-1 && m_currentStyleId) |
693 | 6.46k | { |
694 | 6.46k | CDRStyle tmpStyle; |
695 | 6.46k | m_ps.getRecursedStyle(tmpStyle, m_currentStyleId); |
696 | 6.46k | m_currentFillStyle = tmpStyle.m_fillStyle; |
697 | 6.46k | } |
698 | | |
699 | 66.6k | if (m_fillOpacity < 1.0) |
700 | 33 | propList.insert("draw:opacity", m_fillOpacity, librevenge::RVNG_PERCENT); |
701 | 66.6k | if (m_currentFillStyle.fillType == 0) |
702 | 4.69k | propList.insert("draw:fill", "none"); |
703 | 61.9k | else |
704 | 61.9k | { |
705 | 61.9k | if (m_currentFillStyle.fillType == (unsigned short)-1) |
706 | 11.8k | propList.insert("draw:fill", "none"); |
707 | 50.0k | else |
708 | 50.0k | { |
709 | 50.0k | switch (m_currentFillStyle.fillType) |
710 | 50.0k | { |
711 | 1.47k | case 1: // Solid |
712 | 1.47k | propList.insert("draw:fill", "solid"); |
713 | 1.47k | propList.insert("draw:fill-color", m_ps.getRGBColorString(m_currentFillStyle.color1)); |
714 | 1.47k | propList.insert("svg:fill-rule", "evenodd"); |
715 | 1.47k | break; |
716 | 43.0k | case 2: // Gradient |
717 | 43.0k | if (m_currentFillStyle.gradient.m_stops.empty()) |
718 | 235 | propList.insert("draw:fill", "none"); |
719 | 42.8k | else if (m_currentFillStyle.gradient.m_stops.size() == 1) |
720 | 88 | { |
721 | 88 | propList.insert("draw:fill", "solid"); |
722 | 88 | propList.insert("draw:fill-color", m_ps.getRGBColorString(m_currentFillStyle.gradient.m_stops[0].m_color)); |
723 | 88 | propList.insert("svg:fill-rule", "evenodd"); |
724 | 88 | } |
725 | 42.7k | else if (m_currentFillStyle.gradient.m_stops.size() == 2) |
726 | 41.0k | { |
727 | 41.0k | double angle = m_currentFillStyle.gradient.m_angle * 180 / M_PI; |
728 | 41.0k | normalizeAngle(angle); |
729 | 41.0k | propList.insert("draw:fill", "gradient"); |
730 | 41.0k | propList.insert("draw:start-color", m_ps.getRGBColorString(m_currentFillStyle.gradient.m_stops[0].m_color)); |
731 | 41.0k | propList.insert("draw:end-color", m_ps.getRGBColorString(m_currentFillStyle.gradient.m_stops[1].m_color)); |
732 | 41.0k | propList.insert("draw:angle", (int)angle); |
733 | 41.0k | switch (m_currentFillStyle.gradient.m_type) |
734 | 41.0k | { |
735 | 460 | case 1: // linear |
736 | 467 | case 3: // conical |
737 | 467 | propList.insert("draw:style", "linear"); |
738 | 467 | angle += 90.0; |
739 | 467 | normalizeAngle(angle); |
740 | 467 | propList.insert("draw:angle", (int)angle); |
741 | 467 | propList.insert("draw:border", (double)(m_currentFillStyle.gradient.m_edgeOffset)/100.0, librevenge::RVNG_PERCENT); |
742 | 467 | break; |
743 | 40.3k | case 2: // radial |
744 | 40.3k | propList.insert("draw:border", (2.0 * (double)(m_currentFillStyle.gradient.m_edgeOffset)/100.0), librevenge::RVNG_PERCENT); |
745 | 40.3k | propList.insert("draw:style", "radial"); |
746 | 40.3k | propList.insert("svg:cx", (double)(0.5 + m_currentFillStyle.gradient.m_centerXOffset/200.0), librevenge::RVNG_PERCENT); |
747 | 40.3k | propList.insert("svg:cy", (double)(0.5 + m_currentFillStyle.gradient.m_centerXOffset/200.0), librevenge::RVNG_PERCENT); |
748 | 40.3k | break; |
749 | 42 | case 4: // square |
750 | 42 | propList.insert("draw:border", (2.0 * (double)(m_currentFillStyle.gradient.m_edgeOffset)/100.0), librevenge::RVNG_PERCENT); |
751 | 42 | propList.insert("draw:style", "square"); |
752 | 42 | propList.insert("svg:cx", (double)(0.5 + m_currentFillStyle.gradient.m_centerXOffset/200.0), librevenge::RVNG_PERCENT); |
753 | 42 | propList.insert("svg:cy", (double)(0.5 + m_currentFillStyle.gradient.m_centerXOffset/200.0), librevenge::RVNG_PERCENT); |
754 | 42 | break; |
755 | 206 | default: |
756 | 206 | propList.insert("draw:style", "linear"); |
757 | 206 | angle += 90.0; |
758 | 206 | normalizeAngle(angle); |
759 | 206 | propList.insert("draw:angle", (int)angle); |
760 | 206 | librevenge::RVNGPropertyListVector vec; |
761 | 206 | for (auto &gradStop : m_currentFillStyle.gradient.m_stops) |
762 | 412 | { |
763 | 412 | librevenge::RVNGPropertyList stopElement; |
764 | 412 | stopElement.insert("svg:offset", gradStop.m_offset, librevenge::RVNG_PERCENT); |
765 | 412 | stopElement.insert("svg:stop-color", m_ps.getRGBColorString(gradStop.m_color)); |
766 | 412 | stopElement.insert("svg:stop-opacity", m_fillOpacity, librevenge::RVNG_PERCENT); |
767 | 412 | vec.append(stopElement); |
768 | 412 | } |
769 | 206 | propList.insert("svg:linearGradient", vec); |
770 | 206 | break; |
771 | 41.0k | } |
772 | 41.0k | } |
773 | 1.64k | else // output svg gradient as a hail mary pass towards ODG that does not really support it |
774 | 1.64k | { |
775 | 1.64k | propList.insert("draw:fill", "gradient"); |
776 | 1.64k | propList.insert("draw:style", "linear"); |
777 | 1.64k | double angle = m_currentFillStyle.gradient.m_angle * 180 / M_PI; |
778 | 1.64k | angle += 90.0; |
779 | 1.64k | normalizeAngle(angle); |
780 | 1.64k | propList.insert("draw:angle", (int)angle); |
781 | 1.64k | librevenge::RVNGPropertyListVector vec; |
782 | 1.64k | for (auto &gradStop : m_currentFillStyle.gradient.m_stops) |
783 | 512k | { |
784 | 512k | librevenge::RVNGPropertyList stopElement; |
785 | 512k | stopElement.insert("svg:offset", gradStop.m_offset, librevenge::RVNG_PERCENT); |
786 | 512k | stopElement.insert("svg:stop-color", m_ps.getRGBColorString(gradStop.m_color)); |
787 | 512k | stopElement.insert("svg:stop-opacity", m_fillOpacity, librevenge::RVNG_PERCENT); |
788 | 512k | vec.append(stopElement); |
789 | 512k | } |
790 | 1.64k | propList.insert("svg:linearGradient", vec); |
791 | 1.64k | } |
792 | 43.0k | break; |
793 | 43.0k | case 7: // Pattern |
794 | 1.20k | case 8: // Pattern |
795 | 1.20k | { |
796 | 1.20k | auto iterPattern = m_ps.m_patterns.find(m_currentFillStyle.imageFill.id); |
797 | 1.20k | if (iterPattern != m_ps.m_patterns.end()) |
798 | 323 | { |
799 | 323 | propList.insert("draw:fill", "bitmap"); |
800 | 323 | librevenge::RVNGBinaryData image; |
801 | 323 | _generateBitmapFromPattern(image, iterPattern->second, m_currentFillStyle.color1, m_currentFillStyle.color2); |
802 | | #if DUMP_PATTERN |
803 | | librevenge::RVNGString filename; |
804 | | filename.sprintf("pattern%.8x.bmp", m_currentFillStyle.imageFill.id); |
805 | | FILE *f = fopen(filename.cstr(), "wb"); |
806 | | if (f) |
807 | | { |
808 | | const unsigned char *tmpBuffer = image.getDataBuffer(); |
809 | | for (unsigned long k = 0; k < image.size(); k++) |
810 | | fprintf(f, "%c",tmpBuffer[k]); |
811 | | fclose(f); |
812 | | } |
813 | | #endif |
814 | 323 | propList.insert("draw:fill-image", image); |
815 | 323 | propList.insert("librevenge:mime-type", "image/bmp"); |
816 | 323 | propList.insert("style:repeat", "repeat"); |
817 | 323 | if (m_currentFillStyle.imageFill.isRelative) |
818 | 0 | { |
819 | 0 | propList.insert("svg:width", m_currentFillStyle.imageFill.width, librevenge::RVNG_PERCENT); |
820 | 0 | propList.insert("svg:height", m_currentFillStyle.imageFill.height, librevenge::RVNG_PERCENT); |
821 | 0 | } |
822 | 323 | else |
823 | 323 | { |
824 | 323 | double scaleX = 1.0; |
825 | 323 | double scaleY = 1.0; |
826 | 323 | if (m_currentFillStyle.imageFill.flags & 0x04) // scale fill with image |
827 | 0 | { |
828 | 0 | scaleX = m_currentTransforms.getScaleX(); |
829 | 0 | scaleY = m_currentTransforms.getScaleY(); |
830 | 0 | } |
831 | 323 | propList.insert("svg:width", m_currentFillStyle.imageFill.width * scaleX); |
832 | 323 | propList.insert("svg:height", m_currentFillStyle.imageFill.height * scaleY); |
833 | 323 | } |
834 | 323 | propList.insert("draw:fill-image-ref-point", "bottom-left"); |
835 | 323 | if (m_currentFillStyle.imageFill.isRelative) |
836 | 0 | { |
837 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset)) |
838 | 0 | propList.insert("draw:fill-image-ref-point-x", m_currentFillStyle.imageFill.xOffset, librevenge::RVNG_PERCENT); |
839 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset)) |
840 | 0 | propList.insert("draw:fill-image-ref-point-y", m_currentFillStyle.imageFill.yOffset, librevenge::RVNG_PERCENT); |
841 | 0 | } |
842 | 323 | else |
843 | 323 | { |
844 | 323 | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateX())) |
845 | 0 | { |
846 | 0 | double xOffset = m_fillTransforms.getTranslateX() / m_currentFillStyle.imageFill.width; |
847 | 0 | normalize(xOffset); |
848 | 0 | propList.insert("draw:fill-image-ref-point-x", xOffset, librevenge::RVNG_PERCENT); |
849 | 0 | } |
850 | 323 | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateY())) |
851 | 0 | { |
852 | 0 | double yOffset = m_fillTransforms.getTranslateY() / m_currentFillStyle.imageFill.width; |
853 | 0 | normalize(yOffset); |
854 | 0 | propList.insert("draw:fill-image-ref-point-y", 1.0 - yOffset, librevenge::RVNG_PERCENT); |
855 | 0 | } |
856 | 323 | } |
857 | 323 | } |
858 | 886 | else |
859 | 886 | { |
860 | | // We did not find the pattern, so fill solid with the background colour |
861 | 886 | propList.insert("draw:fill", "solid"); |
862 | 886 | propList.insert("draw:fill-color", m_ps.getRGBColorString(m_currentFillStyle.color2)); |
863 | 886 | propList.insert("svg:fill-rule", "evenodd"); |
864 | 886 | } |
865 | 1.20k | } |
866 | 1.20k | break; |
867 | 1.77k | case 9: // Bitmap |
868 | 3.01k | case 11: // Texture |
869 | 3.01k | { |
870 | 3.01k | auto iterBmp = m_ps.m_bmps.find(m_currentFillStyle.imageFill.id); |
871 | 3.01k | if (iterBmp != m_ps.m_bmps.end()) |
872 | 1.44k | { |
873 | 1.44k | propList.insert("librevenge:mime-type", "image/bmp"); |
874 | 1.44k | propList.insert("draw:fill", "bitmap"); |
875 | 1.44k | propList.insert("draw:fill-image", iterBmp->second); |
876 | 1.44k | propList.insert("style:repeat", "repeat"); |
877 | 1.44k | if (m_currentFillStyle.imageFill.isRelative) |
878 | 0 | { |
879 | 0 | propList.insert("svg:width", m_currentFillStyle.imageFill.width, librevenge::RVNG_PERCENT); |
880 | 0 | propList.insert("svg:height", m_currentFillStyle.imageFill.height, librevenge::RVNG_PERCENT); |
881 | 0 | } |
882 | 1.44k | else |
883 | 1.44k | { |
884 | 1.44k | double scaleX = 1.0; |
885 | 1.44k | double scaleY = 1.0; |
886 | 1.44k | if (m_currentFillStyle.imageFill.flags & 0x04) // scale fill with image |
887 | 0 | { |
888 | 0 | scaleX = m_currentTransforms.getScaleX(); |
889 | 0 | scaleY = m_currentTransforms.getScaleY(); |
890 | 0 | } |
891 | 1.44k | propList.insert("svg:width", m_currentFillStyle.imageFill.width * scaleX); |
892 | 1.44k | propList.insert("svg:height", m_currentFillStyle.imageFill.height * scaleY); |
893 | 1.44k | } |
894 | 1.44k | propList.insert("draw:fill-image-ref-point", "bottom-left"); |
895 | 1.44k | if (m_currentFillStyle.imageFill.isRelative) |
896 | 0 | { |
897 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset)) |
898 | 0 | propList.insert("draw:fill-image-ref-point-x", m_currentFillStyle.imageFill.xOffset, librevenge::RVNG_PERCENT); |
899 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset)) |
900 | 0 | propList.insert("draw:fill-image-ref-point-y", m_currentFillStyle.imageFill.yOffset, librevenge::RVNG_PERCENT); |
901 | 0 | } |
902 | 1.44k | else |
903 | 1.44k | { |
904 | 1.44k | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateX())) |
905 | 0 | { |
906 | 0 | double xOffset = m_fillTransforms.getTranslateX() / m_currentFillStyle.imageFill.width; |
907 | 0 | while (xOffset < 0.0) |
908 | 0 | xOffset += 1.0; |
909 | 0 | while (xOffset > 1.0) |
910 | 0 | xOffset -= 1.0; |
911 | 0 | propList.insert("draw:fill-image-ref-point-x", xOffset, librevenge::RVNG_PERCENT); |
912 | 0 | } |
913 | 1.44k | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateY())) |
914 | 0 | { |
915 | 0 | double yOffset = m_fillTransforms.getTranslateY() / m_currentFillStyle.imageFill.width; |
916 | 0 | while (yOffset < 0.0) |
917 | 0 | yOffset += 1.0; |
918 | 0 | while (yOffset > 1.0) |
919 | 0 | yOffset -= 1.0; |
920 | 0 | propList.insert("draw:fill-image-ref-point-y", 1.0 - yOffset, librevenge::RVNG_PERCENT); |
921 | 0 | } |
922 | 1.44k | } |
923 | 1.44k | } |
924 | 1.57k | else |
925 | 1.57k | propList.insert("draw:fill", "none"); |
926 | 3.01k | } |
927 | 3.01k | break; |
928 | 327 | case 10: // Full color |
929 | 327 | { |
930 | 327 | auto iterVect = m_ps.m_vects.find(m_currentFillStyle.imageFill.id); |
931 | 327 | if (iterVect != m_ps.m_vects.end()) |
932 | 0 | { |
933 | 0 | propList.insert("draw:fill", "bitmap"); |
934 | 0 | propList.insert("librevenge:mime-type", "image/svg+xml"); |
935 | 0 | propList.insert("draw:fill-image", iterVect->second); |
936 | 0 | propList.insert("style:repeat", "repeat"); |
937 | 0 | if (m_currentFillStyle.imageFill.isRelative) |
938 | 0 | { |
939 | 0 | propList.insert("svg:width", m_currentFillStyle.imageFill.width, librevenge::RVNG_PERCENT); |
940 | 0 | propList.insert("svg:height", m_currentFillStyle.imageFill.height, librevenge::RVNG_PERCENT); |
941 | 0 | } |
942 | 0 | else |
943 | 0 | { |
944 | 0 | double scaleX = 1.0; |
945 | 0 | double scaleY = 1.0; |
946 | 0 | if (m_currentFillStyle.imageFill.flags & 0x04) // scale fill with image |
947 | 0 | { |
948 | 0 | scaleX = m_currentTransforms.getScaleX(); |
949 | 0 | scaleY = m_currentTransforms.getScaleY(); |
950 | 0 | } |
951 | 0 | propList.insert("svg:width", m_currentFillStyle.imageFill.width * scaleX); |
952 | 0 | propList.insert("svg:height", m_currentFillStyle.imageFill.height * scaleY); |
953 | 0 | } |
954 | 0 | propList.insert("draw:fill-image-ref-point", "bottom-left"); |
955 | 0 | if (m_currentFillStyle.imageFill.isRelative) |
956 | 0 | { |
957 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.xOffset)) |
958 | 0 | propList.insert("draw:fill-image-ref-point-x", m_currentFillStyle.imageFill.xOffset, librevenge::RVNG_PERCENT); |
959 | 0 | if (!CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset) && !CDR_ALMOST_ZERO(m_currentFillStyle.imageFill.yOffset)) |
960 | 0 | propList.insert("draw:fill-image-ref-point-y", m_currentFillStyle.imageFill.yOffset, librevenge::RVNG_PERCENT); |
961 | 0 | } |
962 | 0 | else |
963 | 0 | { |
964 | 0 | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateX())) |
965 | 0 | { |
966 | 0 | double xOffset = m_fillTransforms.getTranslateX() / m_currentFillStyle.imageFill.width; |
967 | 0 | while (xOffset < 0.0) |
968 | 0 | xOffset += 1.0; |
969 | 0 | while (xOffset > 1.0) |
970 | 0 | xOffset -= 1.0; |
971 | 0 | propList.insert("draw:fill-image-ref-point-x", xOffset, librevenge::RVNG_PERCENT); |
972 | 0 | } |
973 | 0 | if (!CDR_ALMOST_ZERO(m_fillTransforms.getTranslateY())) |
974 | 0 | { |
975 | 0 | double yOffset = m_fillTransforms.getTranslateY() / m_currentFillStyle.imageFill.width; |
976 | 0 | while (yOffset < 0.0) |
977 | 0 | yOffset += 1.0; |
978 | 0 | while (yOffset > 1.0) |
979 | 0 | yOffset -= 1.0; |
980 | 0 | propList.insert("draw:fill-image-ref-point-y", 1.0 - yOffset, librevenge::RVNG_PERCENT); |
981 | 0 | } |
982 | 0 | } |
983 | 0 | } |
984 | 327 | else |
985 | 327 | propList.insert("draw:fill", "none"); |
986 | 327 | } |
987 | 327 | break; |
988 | 1.01k | default: |
989 | 1.01k | propList.insert("draw:fill", "none"); |
990 | 1.01k | break; |
991 | 50.0k | } |
992 | 50.0k | } |
993 | 61.9k | } |
994 | 66.6k | } |
995 | | |
996 | | void libcdr::CDRContentCollector::_lineProperties(librevenge::RVNGPropertyList &propList) |
997 | 66.6k | { |
998 | 66.6k | if (m_currentLineStyle.lineType == (unsigned short)-1 && m_currentStyleId) |
999 | 7.92k | { |
1000 | 7.92k | CDRStyle tmpStyle; |
1001 | 7.92k | m_ps.getRecursedStyle(tmpStyle, m_currentStyleId); |
1002 | 7.92k | m_currentLineStyle = tmpStyle.m_lineStyle; |
1003 | 7.92k | } |
1004 | | |
1005 | 66.6k | if (m_currentLineStyle.lineType == (unsigned short)-1) |
1006 | | /* No line style specified and also no line style from the style id, |
1007 | | the shape has no outline then. */ |
1008 | 13.0k | propList.insert("draw:stroke", "none"); |
1009 | 53.5k | else |
1010 | 53.5k | { |
1011 | 53.5k | if (m_currentLineStyle.lineType & 0x1) |
1012 | 145 | propList.insert("draw:stroke", "none"); |
1013 | 53.3k | else if (m_currentLineStyle.lineType & 0x6) |
1014 | 51.4k | { |
1015 | 51.4k | if (m_currentLineStyle.dashArray.size() && (m_currentLineStyle.lineType & 0x4)) |
1016 | 3.30k | propList.insert("draw:stroke", "dash"); |
1017 | 48.1k | else |
1018 | 48.1k | propList.insert("draw:stroke", "solid"); |
1019 | 51.4k | double scale = 1.0; |
1020 | 51.4k | if (m_currentLineStyle.lineType & 0x20) // scale line with image |
1021 | 3.65k | { |
1022 | 3.65k | scale = m_currentTransforms.getScaleX(); |
1023 | 3.65k | double scaleY = m_currentTransforms.getScaleY(); |
1024 | 3.65k | if (scaleY > scale) |
1025 | 33 | scale = scaleY; |
1026 | 3.65k | } |
1027 | 51.4k | scale *= m_currentLineStyle.stretch; |
1028 | 51.4k | propList.insert("svg:stroke-width", m_currentLineStyle.lineWidth * scale); |
1029 | 51.4k | propList.insert("svg:stroke-color", m_ps.getRGBColorString(m_currentLineStyle.color)); |
1030 | | |
1031 | 51.4k | switch (m_currentLineStyle.capsType) |
1032 | 51.4k | { |
1033 | 27 | case 1: |
1034 | 27 | propList.insert("svg:stroke-linecap", "round"); |
1035 | 27 | break; |
1036 | 18 | case 2: |
1037 | 18 | propList.insert("svg:stroke-linecap", "square"); |
1038 | 18 | break; |
1039 | 51.4k | default: |
1040 | 51.4k | propList.insert("svg:stroke-linecap", "butt"); |
1041 | 51.4k | } |
1042 | | |
1043 | 51.4k | switch (m_currentLineStyle.joinType) |
1044 | 51.4k | { |
1045 | 168 | case 1: |
1046 | 168 | propList.insert("svg:stroke-linejoin", "round"); |
1047 | 168 | break; |
1048 | 24 | case 2: |
1049 | 24 | propList.insert("svg:stroke-linejoin", "bevel"); |
1050 | 24 | break; |
1051 | 51.2k | default: |
1052 | 51.2k | propList.insert("svg:stroke-linejoin", "miter"); |
1053 | 51.4k | } |
1054 | | |
1055 | 51.4k | if (m_currentLineStyle.dashArray.size()) |
1056 | 46.5k | { |
1057 | 46.5k | int dots1 = 0; |
1058 | 46.5k | int dots2 = 0; |
1059 | 46.5k | unsigned dots1len = 0; |
1060 | 46.5k | unsigned dots2len = 0; |
1061 | 46.5k | unsigned gap = 0; |
1062 | | |
1063 | 46.5k | if (m_currentLineStyle.dashArray.size() >= 2) |
1064 | 45.6k | { |
1065 | 45.6k | dots1len = m_currentLineStyle.dashArray[0]; |
1066 | 45.6k | gap = m_currentLineStyle.dashArray[1]; |
1067 | 45.6k | } |
1068 | | |
1069 | 46.5k | unsigned long count = m_currentLineStyle.dashArray.size() / 2; |
1070 | 46.5k | unsigned i = 0; |
1071 | 95.3k | for (; i < count;) |
1072 | 51.6k | { |
1073 | 51.6k | if (dots1len == m_currentLineStyle.dashArray[2*i]) |
1074 | 48.7k | dots1++; |
1075 | 2.86k | else |
1076 | 2.86k | break; |
1077 | 48.7k | gap = gap < m_currentLineStyle.dashArray[2*i+1] ? m_currentLineStyle.dashArray[2*i+1] : gap; |
1078 | 48.7k | i++; |
1079 | 48.7k | } |
1080 | 46.5k | if (i < count) |
1081 | 2.86k | { |
1082 | 2.86k | dots2len = m_currentLineStyle.dashArray[2*i]; |
1083 | 2.86k | gap = gap < m_currentLineStyle.dashArray[2*i+1] ? m_currentLineStyle.dashArray[2*i+1] : gap; |
1084 | 2.86k | } |
1085 | 50.7k | for (; i < count;) |
1086 | 6.26k | { |
1087 | 6.26k | if (dots2len == m_currentLineStyle.dashArray[2*i]) |
1088 | 4.21k | dots2++; |
1089 | 2.04k | else |
1090 | 2.04k | break; |
1091 | 4.21k | gap = gap < m_currentLineStyle.dashArray[2*i+1] ? m_currentLineStyle.dashArray[2*i+1] : gap; |
1092 | 4.21k | i++; |
1093 | 4.21k | } |
1094 | 46.5k | if (!dots2) |
1095 | 43.7k | { |
1096 | 43.7k | dots2 = dots1; |
1097 | 43.7k | dots2len = dots1len; |
1098 | 43.7k | } |
1099 | 46.5k | propList.insert("draw:dots1", dots1); |
1100 | 46.5k | propList.insert("draw:dots1-length", 72.0*(m_currentLineStyle.lineWidth * scale)*dots1len, librevenge::RVNG_POINT); |
1101 | 46.5k | propList.insert("draw:dots2", dots2); |
1102 | 46.5k | propList.insert("draw:dots2-length", 72.0*(m_currentLineStyle.lineWidth * scale)*dots2len, librevenge::RVNG_POINT); |
1103 | 46.5k | propList.insert("draw:distance", 72.0*(m_currentLineStyle.lineWidth * scale)*gap, librevenge::RVNG_POINT); |
1104 | 46.5k | } |
1105 | 51.4k | } |
1106 | 1.93k | else |
1107 | 1.93k | { |
1108 | 1.93k | propList.insert("draw:stroke", "solid"); |
1109 | 1.93k | propList.insert("svg:stroke-width", 0.0); |
1110 | 1.93k | propList.insert("svg:stroke-color", "#000000"); |
1111 | 1.93k | } |
1112 | 53.5k | } |
1113 | | |
1114 | | // Deal with line markers (arrows, etc.) |
1115 | 66.6k | if (!m_currentLineStyle.startMarker.empty()) |
1116 | 2.28k | { |
1117 | 2.28k | CDRPath startMarker(m_currentLineStyle.startMarker); |
1118 | 2.28k | startMarker.transform(m_currentTransforms); |
1119 | 2.28k | if (!m_groupTransforms.empty()) |
1120 | 3 | startMarker.transform(m_groupTransforms.top()); |
1121 | 2.28k | CDRTransform tmpTrafo = CDRTransform(1.0, 0.0, 0.0, 0.0, -1.0, 0); |
1122 | 2.28k | startMarker.transform(tmpTrafo); |
1123 | 2.28k | librevenge::RVNGString path, viewBox; |
1124 | 2.28k | double width; |
1125 | 2.28k | startMarker.writeOut(path, viewBox, width); |
1126 | 2.28k | propList.insert("draw:marker-start-viewbox", viewBox); |
1127 | 2.28k | propList.insert("draw:marker-start-path", path); |
1128 | | // propList.insert("draw:marker-start-width", width); |
1129 | 2.28k | } |
1130 | 66.6k | if (!m_currentLineStyle.endMarker.empty()) |
1131 | 2.50k | { |
1132 | 2.50k | CDRPath endMarker(m_currentLineStyle.endMarker); |
1133 | 2.50k | endMarker.transform(m_currentTransforms); |
1134 | 2.50k | if (!m_groupTransforms.empty()) |
1135 | 1 | endMarker.transform(m_groupTransforms.top()); |
1136 | 2.50k | CDRTransform tmpTrafo = CDRTransform(-1.0, 0.0, 0.0, 0.0, -1.0, 0); |
1137 | 2.50k | endMarker.transform(tmpTrafo); |
1138 | 2.50k | librevenge::RVNGString path, viewBox; |
1139 | 2.50k | double width; |
1140 | 2.50k | endMarker.writeOut(path, viewBox, width); |
1141 | 2.50k | propList.insert("draw:marker-end-viewbox", viewBox); |
1142 | 2.50k | propList.insert("draw:marker-end-path", path); |
1143 | | // propList.insert("draw:marker-end-width", width); |
1144 | 2.50k | } |
1145 | | |
1146 | | |
1147 | | |
1148 | 66.6k | } |
1149 | | |
1150 | | void libcdr::CDRContentCollector::_generateBitmapFromPattern(librevenge::RVNGBinaryData &bitmap, const CDRPattern &pattern, const CDRColor &fgColor, const CDRColor &bgColor) |
1151 | 323 | { |
1152 | 323 | unsigned height = pattern.height; |
1153 | 323 | unsigned width = pattern.width; |
1154 | 323 | auto tmpPixelSize = (unsigned)(height * width); |
1155 | 323 | if (tmpPixelSize < (unsigned)height) // overflow |
1156 | 0 | return; |
1157 | | |
1158 | 323 | unsigned tmpDIBImageSize = tmpPixelSize * 4; |
1159 | 323 | if (tmpPixelSize > tmpDIBImageSize) // overflow !!! |
1160 | 0 | return; |
1161 | | |
1162 | 323 | unsigned tmpDIBOffsetBits = 14 + 40; |
1163 | 323 | unsigned tmpDIBFileSize = tmpDIBOffsetBits + tmpDIBImageSize; |
1164 | 323 | if (tmpDIBImageSize > tmpDIBFileSize) // overflow !!! |
1165 | 0 | return; |
1166 | | |
1167 | | // Create DIB file header |
1168 | 323 | writeU16(bitmap, 0x4D42); // Type |
1169 | 323 | writeU32(bitmap, (int)tmpDIBFileSize); // Size |
1170 | 323 | writeU16(bitmap, 0); // Reserved1 |
1171 | 323 | writeU16(bitmap, 0); // Reserved2 |
1172 | 323 | writeU32(bitmap, (int)tmpDIBOffsetBits); // OffsetBits |
1173 | | |
1174 | | // Create DIB Info header |
1175 | 323 | writeU32(bitmap, 40); // Size |
1176 | | |
1177 | 323 | writeU32(bitmap, (int)width); // Width |
1178 | 323 | writeU32(bitmap, (int)height); // Height |
1179 | | |
1180 | 323 | writeU16(bitmap, 1); // Planes |
1181 | 323 | writeU16(bitmap, 32); // BitCount |
1182 | 323 | writeU32(bitmap, 0); // Compression |
1183 | 323 | writeU32(bitmap, (int)tmpDIBImageSize); // SizeImage |
1184 | 323 | writeU32(bitmap, 0); // XPelsPerMeter |
1185 | 323 | writeU32(bitmap, 0); // YPelsPerMeter |
1186 | 323 | writeU32(bitmap, 0); // ColorsUsed |
1187 | 323 | writeU32(bitmap, 0); // ColorsImportant |
1188 | | |
1189 | | // The Bitmaps in CDR are padded to 32bit border |
1190 | 323 | unsigned lineWidth = (width + 7) / 8; |
1191 | | |
1192 | 323 | unsigned foreground = m_ps._getRGBColor(fgColor); |
1193 | 323 | unsigned background = m_ps._getRGBColor(bgColor); |
1194 | | |
1195 | 899 | for (unsigned j = height; j > 0; --j) |
1196 | 576 | { |
1197 | 576 | unsigned i = 0; |
1198 | 576 | unsigned k = 0; |
1199 | 17.2k | while (i <lineWidth && k < width) |
1200 | 16.6k | { |
1201 | 16.6k | unsigned l = 0; |
1202 | 16.6k | unsigned char c = 0; |
1203 | 16.6k | const unsigned index = (j-1)*lineWidth+i; |
1204 | 16.6k | if (index < pattern.pattern.size()) |
1205 | 16.6k | c = pattern.pattern[index]; |
1206 | 16.6k | i++; |
1207 | 149k | while (k < width && l < 8) |
1208 | 133k | { |
1209 | 133k | if (c & 0x80) |
1210 | 101k | writeU32(bitmap, (int)background); |
1211 | 32.0k | else |
1212 | 32.0k | writeU32(bitmap, (int)foreground); |
1213 | 133k | c <<= 1; |
1214 | 133k | l++; |
1215 | 133k | k++; |
1216 | 133k | } |
1217 | 16.6k | } |
1218 | 576 | } |
1219 | 323 | } |
1220 | | |
1221 | | void libcdr::CDRContentCollector::collectBitmap(unsigned imageId, double x1, double x2, double y1, double y2) |
1222 | 8.11k | { |
1223 | 8.11k | auto iter = m_ps.m_bmps.find(imageId); |
1224 | 8.11k | if (iter != m_ps.m_bmps.end()) |
1225 | 4.75k | m_currentImage = CDRImage(iter->second, x1, x2, y1, y2); |
1226 | 8.11k | } |
1227 | | |
1228 | | void libcdr::CDRContentCollector::collectPpdt(const std::vector<std::pair<double, double> > &points, const std::vector<unsigned> &knotVector) |
1229 | 1.97k | { |
1230 | 1.97k | m_splineData = CDRSplineData(points, knotVector); |
1231 | 1.97k | } |
1232 | | |
1233 | | void libcdr::CDRContentCollector::collectFillOpacity(double opacity) |
1234 | 180 | { |
1235 | 180 | m_fillOpacity = opacity; |
1236 | 180 | } |
1237 | | |
1238 | | void libcdr::CDRContentCollector::collectBBox(double x0, double y0, double x1, double y1) |
1239 | 8.11k | { |
1240 | 8.11k | CDRBox bBox(x0, y0, x1, y1); |
1241 | 8.11k | if (m_currentVectLevel && CDR_ALMOST_ZERO(m_page.width) && CDR_ALMOST_ZERO(m_page.height)) |
1242 | 162 | { |
1243 | 162 | m_page.width = bBox.getWidth(); |
1244 | 162 | m_page.height = bBox.getHeight(); |
1245 | 162 | m_page.offsetX = bBox.getMinX(); |
1246 | 162 | m_page.offsetY = bBox.getMinY(); |
1247 | 162 | } |
1248 | 8.11k | m_currentBBox = bBox; |
1249 | 8.11k | } |
1250 | | |
1251 | | void libcdr::CDRContentCollector::collectSpnd(unsigned spnd) |
1252 | 5.56k | { |
1253 | 5.56k | if (m_currentVectLevel && !m_spnd) |
1254 | 125 | m_spnd = spnd; |
1255 | 5.43k | else if (!m_currentVectLevel) |
1256 | 5.38k | m_spnd = spnd; |
1257 | 5.56k | } |
1258 | | |
1259 | | void libcdr::CDRContentCollector::collectVectorPattern(unsigned id, const librevenge::RVNGBinaryData &data) |
1260 | 20.5k | { |
1261 | 20.5k | librevenge::RVNGInputStream *input = data.getDataStream(); |
1262 | 20.5k | if (!input) |
1263 | 0 | return; |
1264 | | |
1265 | 20.5k | input->seek(0, librevenge::RVNG_SEEK_SET); |
1266 | 20.5k | if (!libcdr::CMXDocument::isSupported(input)) |
1267 | 2.46k | return; |
1268 | 18.0k | input->seek(0, librevenge::RVNG_SEEK_SET); |
1269 | 18.0k | librevenge::RVNGStringVector svgOutput; |
1270 | 18.0k | librevenge::RVNGSVGDrawingGenerator generator(svgOutput, ""); |
1271 | 18.0k | if (!libcdr::CMXDocument::parse(input, &generator)) |
1272 | 18.0k | return; |
1273 | 0 | if (!svgOutput.empty()) |
1274 | 0 | { |
1275 | 0 | const char *header = |
1276 | 0 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"; |
1277 | 0 | librevenge::RVNGBinaryData output((const unsigned char *)header, strlen(header)); |
1278 | 0 | output.append((const unsigned char *)svgOutput[0].cstr(), strlen(svgOutput[0].cstr())); |
1279 | 0 | m_ps.m_vects[id] = output; |
1280 | 0 | } |
1281 | | #if DUMP_VECT |
1282 | | librevenge::RVNGString filename; |
1283 | | filename.sprintf("vect%.8x.cmx", id); |
1284 | | FILE *f = fopen(filename.cstr(), "wb"); |
1285 | | if (f) |
1286 | | { |
1287 | | const unsigned char *tmpBuffer = data.getDataBuffer(); |
1288 | | for (unsigned long k = 0; k < data.size(); k++) |
1289 | | fprintf(f, "%c",tmpBuffer[k]); |
1290 | | fclose(f); |
1291 | | } |
1292 | | filename.sprintf("vect%.8x.svg", id); |
1293 | | f = fopen(filename.cstr(), "wb"); |
1294 | | if (f) |
1295 | | { |
1296 | | const unsigned char *tmpBuffer = m_ps.m_vects[id].getDataBuffer(); |
1297 | | for (unsigned long k = 0; k < m_ps.m_vects[id].size(); k++) |
1298 | | fprintf(f, "%c",tmpBuffer[k]); |
1299 | | fclose(f); |
1300 | | } |
1301 | | #endif |
1302 | 0 | } |
1303 | | |
1304 | | void libcdr::CDRContentCollector::collectArtisticText(double x, double y) |
1305 | 3.02k | { |
1306 | 3.02k | m_currentTextBox = CDRBox(x, y, x, y); |
1307 | 3.02k | m_currentBBox.m_w *= 2.0; |
1308 | 3.02k | std::map<unsigned, std::vector<CDRTextLine> >::const_iterator iter = m_ps.m_texts.find(m_spnd); |
1309 | 3.02k | if (iter != m_ps.m_texts.end()) |
1310 | 2.68k | m_currentText = &(iter->second); |
1311 | 3.02k | } |
1312 | | |
1313 | | void libcdr::CDRContentCollector::collectParagraphText(double x, double y, double width, double height) |
1314 | 2.92k | { |
1315 | 2.92k | m_currentTextBox.m_x = x; |
1316 | 2.92k | m_currentTextBox.m_y = y; |
1317 | 2.92k | m_currentTextBox.m_w = width; |
1318 | 2.92k | m_currentTextBox.m_h = height; |
1319 | 2.92k | std::map<unsigned, std::vector<CDRTextLine> >::const_iterator iter = m_ps.m_texts.find(m_spnd); |
1320 | 2.92k | if (iter != m_ps.m_texts.end()) |
1321 | 2.36k | m_currentText = &(iter->second); |
1322 | 2.92k | } |
1323 | | |
1324 | | void libcdr::CDRContentCollector::collectStyleId(unsigned styleId) |
1325 | 9.18k | { |
1326 | 9.18k | m_currentStyleId = styleId; |
1327 | 9.18k | } |
1328 | | |
1329 | | /* vim:set shiftwidth=2 softtabstop=2 expandtab: */ |