/src/libwpg/src/lib/WPG2Parser.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwpg |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
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 | | * Major Contributor(s): |
10 | | * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) |
11 | | * Copyright (C) 2005-2007 Fridrich Strba (fridrich.strba@bluewin.ch) |
12 | | * Copyright (C) 2004 Marc Oude Kotte (marc@solcon.nl) |
13 | | * |
14 | | * For minor contributions see the git repository. |
15 | | * |
16 | | * Alternatively, the contents of this file may be used under the terms |
17 | | * of the GNU Lesser General Public License Version 2.1 or later |
18 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
19 | | * applicable instead of those above. |
20 | | * |
21 | | * For further information visit http://libwpg.sourceforge.net |
22 | | */ |
23 | | |
24 | | /* "This product is not manufactured, approved, or supported by |
25 | | * Corel Corporation or Corel Corporation Limited." |
26 | | */ |
27 | | |
28 | | #include "WPG2Parser.h" |
29 | | |
30 | | #include <cstring> |
31 | | #include <limits> |
32 | | #include <math.h> |
33 | | #include <vector> |
34 | | |
35 | | #include <librevenge/librevenge.h> |
36 | | |
37 | | #include <libwpd/libwpd.h> |
38 | | |
39 | | #include "WPGTextDataHandler.h" |
40 | | #include "libwpg_utils.h" |
41 | | |
42 | | #define DUMP_BINARY_DATA 0 |
43 | | |
44 | | #if DUMP_BINARY_DATA |
45 | | #include <sstream> |
46 | | #endif |
47 | | |
48 | | // MSVC++ 6.0 does not have the macro defined, so we define it |
49 | | #ifndef M_PI |
50 | | #define M_PI 3.14159265358979323846 |
51 | | #endif |
52 | | |
53 | | using namespace libwpd; |
54 | | |
55 | | using libwpg::getRemainingLength; |
56 | | |
57 | | namespace |
58 | | { |
59 | | |
60 | | static double fixedPointToDouble(const unsigned int fixedPointNumber) |
61 | 79.4k | { |
62 | 79.4k | auto fixedPointNumberIntegerPart = (short)((fixedPointNumber & 0xFFFF0000) >> 16); |
63 | 79.4k | auto fixedPointNumberFractionalPart = (double)((double)(fixedPointNumber & 0x0000FFFF)/(double)0xFFFF); |
64 | 79.4k | return ((fixedPointNumberIntegerPart >= 0) ? |
65 | 71.6k | ((double)fixedPointNumberIntegerPart + fixedPointNumberFractionalPart) : |
66 | 79.4k | ((double)fixedPointNumberIntegerPart - fixedPointNumberFractionalPart)); |
67 | 79.4k | } |
68 | | |
69 | | long safeSubtract(long left, const long right) |
70 | 3.88M | { |
71 | 3.88M | if (right > 0) |
72 | 1.00M | { |
73 | 1.00M | if (left > std::numeric_limits<long>::min() + right) |
74 | 1.00M | left -= right; |
75 | 6.33k | else |
76 | 6.33k | left = std::numeric_limits<long>::min(); |
77 | 1.00M | } |
78 | 2.87M | else if (right < 0) |
79 | 2.50M | { |
80 | 2.50M | if (left < std::numeric_limits<long>::max() + right) |
81 | 2.48M | left -= right; |
82 | 20.3k | else |
83 | 20.3k | left = std::numeric_limits<long>::max(); |
84 | 2.50M | } |
85 | 3.88M | return left; |
86 | 3.88M | } |
87 | | |
88 | | } |
89 | | |
90 | | static const unsigned char defaultWPG2PaletteRed[] = |
91 | | { |
92 | | 0x00, 0xFF, 0x7F, 0xBF, 0x00, 0x00, 0x00, 0x7F, |
93 | | 0x7F, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, |
94 | | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
95 | | 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, |
96 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
97 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
98 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
99 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
100 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
101 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
102 | | 0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A, |
103 | | 0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2, |
104 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
105 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
106 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
107 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
108 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
109 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
110 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
111 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
112 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
113 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
114 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
115 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
116 | | 0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A, |
117 | | 0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2, |
118 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
119 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
120 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
121 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
122 | | 0x33, 0x47, 0x61, 0x73, 0x87, 0x9C, 0xB0, 0xC7, |
123 | | 0xCC, 0xD4, 0xDB, 0xE3, 0xE8, 0xF0, 0xF7, 0xFF, |
124 | | }; |
125 | | |
126 | | static const unsigned char defaultWPG2PaletteGreen[] = |
127 | | { |
128 | | 0x00, 0xFF, 0x7F, 0xBF, 0x00, 0x7F, 0x7F, 0x00, |
129 | | 0x00, 0x7F, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, |
130 | | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
131 | | 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, |
132 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
133 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
134 | | 0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A, |
135 | | 0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2, |
136 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
137 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
138 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
139 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
140 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
141 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
142 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
143 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
144 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
145 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
146 | | 0x56, 0x64, 0x72, 0x80, 0x8E, 0x9C, 0xAA, 0xB1, |
147 | | 0xB8, 0xBF, 0xC6, 0xCD, 0xD4, 0xDB, 0xE2, 0xE9, |
148 | | 0x2B, 0x32, 0x39, 0x40, 0x47, 0x4E, 0x55, 0x63, |
149 | | 0x71, 0x7F, 0x8D, 0x9B, 0xA9, 0xB7, 0xC5, 0xD3, |
150 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
151 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
152 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
153 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
154 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
155 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
156 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
157 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
158 | | 0x29, 0x38, 0x45, 0x4F, 0x5C, 0x63, 0x69, 0xD4, |
159 | | 0x87, 0x8F, 0x9C, 0xA8, 0xB3, 0xC4, 0xCF, 0xE0, |
160 | | }; |
161 | | |
162 | | static const unsigned char defaultWPG2PaletteBlue[] = |
163 | | { |
164 | | 0x00, 0xFF, 0x7F, 0xBF, 0x7F, 0x00, 0x7F, 0x00, |
165 | | 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, |
166 | | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
167 | | 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, |
168 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
169 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
170 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
171 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
172 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
173 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
174 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
175 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
176 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, |
177 | | 0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6, |
178 | | 0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A, |
179 | | 0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2, |
180 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF, |
181 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
182 | | 0x7B, 0x91, 0xA7, 0xB0, 0xD3, 0xE4, 0xFF, 0xFF, |
183 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
184 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
185 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
186 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
187 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
188 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
189 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
190 | | 0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF, |
191 | | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
192 | | 0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A, |
193 | | 0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2, |
194 | | 0x11, 0x17, 0x1C, 0x24, 0x29, 0x2B, 0x2B, 0x30, |
195 | | 0x47, 0x57, 0x69, 0x78, 0x8C, 0x9C, 0xB0, 0xC7, |
196 | | }; |
197 | | |
198 | | class WPG2Parser::ObjectCharacterization |
199 | | { |
200 | | public: |
201 | | bool taper; |
202 | | bool translate; |
203 | | bool skew; |
204 | | bool scale; |
205 | | bool rotate; |
206 | | bool hasObjectId; |
207 | | bool editLock; |
208 | | bool windingRule; |
209 | | bool filled; |
210 | | bool closed; |
211 | | bool framed; |
212 | | |
213 | | unsigned long objectId; |
214 | | unsigned long lockFlags; |
215 | | double rotationAngle; |
216 | | long sxcos; |
217 | | long sycos; |
218 | | long kxsin; |
219 | | long kysin; |
220 | | long txinteger; |
221 | | unsigned short txfraction; |
222 | | long tyinteger; |
223 | | unsigned short tyfraction; |
224 | | long px; |
225 | | long py; |
226 | | |
227 | | WPG2TransformMatrix matrix; |
228 | | |
229 | | ObjectCharacterization(): |
230 | 123k | taper(false), |
231 | 123k | translate(false), |
232 | 123k | skew(false), |
233 | 123k | scale(false), |
234 | 123k | rotate(false), |
235 | 123k | hasObjectId(false), |
236 | 123k | editLock(false), |
237 | 123k | windingRule(false), |
238 | 123k | filled(false), |
239 | 123k | closed(false), |
240 | 123k | framed(true), |
241 | 123k | objectId(0), |
242 | 123k | lockFlags(0), |
243 | 123k | rotationAngle(0.0), |
244 | 123k | sxcos(0), |
245 | 123k | sycos(0), |
246 | 123k | kxsin(0), |
247 | 123k | kysin(0), |
248 | 123k | txinteger(0), |
249 | 123k | txfraction(0), |
250 | 123k | tyinteger(0), |
251 | 123k | tyfraction(0), |
252 | 123k | px(0), |
253 | 123k | py(0), |
254 | 123k | matrix() |
255 | 123k | {} |
256 | | }; |
257 | | |
258 | | WPG2Parser::WPG2Parser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter, bool isEmbedded): |
259 | 13.3k | WPGXParser(input, painter), |
260 | 13.3k | m_recordLength(0), |
261 | 13.3k | m_recordEnd(0), |
262 | 13.3k | m_success(true), m_exit(false), m_graphicsStarted(isEmbedded), |
263 | 13.3k | m_xres(1200), m_yres(1200), |
264 | 13.3k | m_xofs(0), m_yofs(0), |
265 | 13.3k | m_width(0), m_height(0), |
266 | 13.3k | m_doublePrecision(false), |
267 | 13.3k | m_style(), |
268 | 13.3k | m_penForeColor(0,0,0), |
269 | 13.3k | m_penBackColor(0xff,0xff,0xff), |
270 | 13.3k | m_brushForeColor(0,0,0), |
271 | 13.3k | m_brushBackColor(0xff,0xff,0xff), |
272 | 13.3k | m_dashArray(), |
273 | 13.3k | m_gradient(), |
274 | 13.3k | m_dashArrayStyles(), |
275 | 13.3k | m_layerOpened(false), |
276 | | #ifdef DEBUG |
277 | | m_layerId(0), |
278 | | #endif |
279 | 13.3k | m_matrix(), |
280 | 13.3k | m_gradientAngle(0.0), |
281 | 13.3k | m_gradientRef(), |
282 | 13.3k | m_groupStack(), |
283 | 13.3k | m_compoundMatrix(), |
284 | 13.3k | m_compoundWindingRule(false), |
285 | 13.3k | m_compoundFilled(false), |
286 | 13.3k | m_compoundFramed(true), |
287 | 13.3k | m_compoundClosed(false), |
288 | 13.3k | m_bitmap(), |
289 | 13.3k | m_binaryData(), |
290 | 13.3k | m_hFlipped(false), |
291 | 13.3k | m_vFlipped(false), |
292 | 13.3k | m_textData(), |
293 | 13.3k | m_drawTextData(false) |
294 | | #if DUMP_BINARY_DATA |
295 | | , m_binaryId(0) |
296 | | #endif |
297 | 13.3k | { |
298 | 13.3k | m_style.insert("draw:fill", "solid"); |
299 | | // default style |
300 | 13.3k | m_penForeColor = libwpg::WPGColor(0,0,0); |
301 | 13.3k | m_penBackColor = libwpg::WPGColor(0xff,0xff,0xff); |
302 | 13.3k | m_style.insert("svg:stroke-width", 0.0); |
303 | 13.3k | m_style.insert("draw:stroke", "solid"); |
304 | 13.3k | m_dashArray = libwpg::WPGDashArray(); |
305 | 13.3k | m_brushForeColor = libwpg::WPGColor(0,0,0); |
306 | 13.3k | m_brushBackColor = libwpg::WPGColor(0xff,0xff,0xff); |
307 | | |
308 | 13.3k | m_style.insert("svg:stroke-color", m_penForeColor.getColorString()); |
309 | 13.3k | m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
310 | 13.3k | m_style.insert("draw:fill-color", m_brushForeColor.getColorString()); |
311 | 13.3k | m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
312 | | |
313 | 13.3k | resetPalette(); |
314 | 13.3k | m_style.insert("draw:fill", "solid"); |
315 | 13.3k | } |
316 | | |
317 | | bool WPG2Parser::parse() |
318 | 13.3k | { |
319 | 13.3k | typedef void (WPG2Parser::*Method)(); |
320 | | |
321 | 13.3k | struct RecordHandler |
322 | 13.3k | { |
323 | 13.3k | int type; |
324 | 13.3k | const char *name; |
325 | 13.3k | Method handler; |
326 | 13.3k | }; |
327 | | |
328 | 13.3k | static const struct RecordHandler handlers[] = |
329 | 13.3k | { |
330 | 13.3k | { 0x01, "Start WPG", &WPG2Parser::handleStartWPG }, |
331 | 13.3k | { 0x02, "End WPG", &WPG2Parser::handleEndWPG }, |
332 | 13.3k | { 0x03, "Form Settings", &WPG2Parser::handleFormSettings }, |
333 | 13.3k | { 0x04, "Ruler Settings", nullptr }, // ignored |
334 | 13.3k | { 0x05, "Grid Settings", nullptr }, // ignored |
335 | 13.3k | { 0x06, "Layer", &WPG2Parser::handleLayer }, |
336 | 13.3k | { 0x08, "Pen Style Definition", &WPG2Parser::handlePenStyleDefinition }, |
337 | 13.3k | { 0x09, "Pattern Definition", &WPG2Parser::handlePatternDefinition }, |
338 | 13.3k | { 0x0a, "Comment", nullptr }, // ignored |
339 | 13.3k | { 0x0b, "Color Transfer", nullptr }, |
340 | 13.3k | { 0x0c, "Color Palette", &WPG2Parser::handleColorPalette }, |
341 | 13.3k | { 0x0d, "DP Color Palette", &WPG2Parser::handleDPColorPalette }, |
342 | 13.3k | { 0x0e, "Bitmap Data", &WPG2Parser::handleBitmapData }, |
343 | 13.3k | { 0x0f, "Text Data", &WPG2Parser::handleTextData }, |
344 | 13.3k | { 0x10, "Chart Style", nullptr }, // ignored |
345 | 13.3k | { 0x11, "Chart Data", nullptr }, // ignored |
346 | 13.3k | { 0x12, "Object Image", &WPG2Parser::handleObjectImage }, |
347 | 13.3k | { 0x15, "Polyline", &WPG2Parser::handlePolyline }, |
348 | 13.3k | { 0x16, "Polyspline", &WPG2Parser::handlePolyspline }, |
349 | 13.3k | { 0x17, "Polycurve", &WPG2Parser::handlePolycurve }, |
350 | 13.3k | { 0x18, "Rectangle", &WPG2Parser::handleRectangle }, |
351 | 13.3k | { 0x19, "Arc", &WPG2Parser::handleArc }, |
352 | 13.3k | { 0x1a, "Compound Polygon", &WPG2Parser::handleCompoundPolygon }, |
353 | 13.3k | { 0x1b, "Bitmap", &WPG2Parser::handleBitmap }, |
354 | 13.3k | { 0x1c, "Text Line", &WPG2Parser::handleTextLine }, |
355 | 13.3k | { 0x1d, "Text Block", &WPG2Parser::handleTextBlock }, |
356 | 13.3k | { 0x1e, "Text Path", &WPG2Parser::handleTextPath }, |
357 | 13.3k | { 0x1f, "Chart", nullptr }, |
358 | 13.3k | { 0x20, "Group", nullptr }, |
359 | 13.3k | { 0x21, "Object Capsule", &WPG2Parser::handleObjectCapsule }, |
360 | 13.3k | { 0x22, "Font Settings", nullptr }, |
361 | 13.3k | { 0x25, "Pen Fore Color", &WPG2Parser::handlePenForeColor }, |
362 | 13.3k | { 0x26, "DP Pen Fore Color", &WPG2Parser::handleDPPenForeColor }, |
363 | 13.3k | { 0x27, "Pen Back Color", &WPG2Parser::handlePenBackColor }, |
364 | 13.3k | { 0x28, "DP Pen Back Color", &WPG2Parser::handleDPPenBackColor }, |
365 | 13.3k | { 0x29, "Pen Style", &WPG2Parser::handlePenStyle }, |
366 | 13.3k | { 0x2a, "Pen Pattern", nullptr }, |
367 | 13.3k | { 0x2b, "Pen Size", &WPG2Parser::handlePenSize }, |
368 | 13.3k | { 0x2c, "DP Pen Size", &WPG2Parser::handleDPPenSize }, |
369 | 13.3k | { 0x2d, "Line Cap", &WPG2Parser::handleLineCap }, |
370 | 13.3k | { 0x2e, "Line Join", &WPG2Parser::handleLineJoin }, |
371 | 13.3k | { 0x2f, "Brush Gradient", &WPG2Parser::handleBrushGradient }, |
372 | 13.3k | { 0x30, "DP Brush Gradient", &WPG2Parser::handleDPBrushGradient }, |
373 | 13.3k | { 0x31, "Brush Fore Color", &WPG2Parser::handleBrushForeColor }, |
374 | 13.3k | { 0x32, "DP Brush Fore Color", &WPG2Parser::handleDPBrushForeColor }, |
375 | 13.3k | { 0x33, "Brush Back Color", &WPG2Parser::handleBrushBackColor }, |
376 | 13.3k | { 0x34, "DP Brush Back Color", &WPG2Parser::handleDPBrushBackColor }, |
377 | 13.3k | { 0x35, "Brush Pattern", &WPG2Parser::handleBrushPattern }, |
378 | 13.3k | { 0x36, "Horizontal Line", nullptr }, |
379 | 13.3k | { 0x37, "Vertical Line", nullptr }, |
380 | 13.3k | { 0x38, "Poster Settings", nullptr }, |
381 | 13.3k | { 0x39, "Image State", nullptr }, |
382 | 13.3k | { 0x3a, "Envelope Definition", nullptr }, |
383 | 13.3k | { 0x3b, "Envelope", nullptr }, |
384 | 13.3k | { 0x3c, "Texture Definition", nullptr }, |
385 | 13.3k | { 0x3d, "Brush Texture", nullptr }, |
386 | 13.3k | { 0x3e, "Texture Alignment", nullptr }, |
387 | 13.3k | { 0x3f, "Pen Texture ", nullptr }, |
388 | 13.3k | { 0x00, nullptr, nullptr } // end marker |
389 | 13.3k | }; |
390 | | |
391 | 680k | while (!m_input->isEnd()) |
392 | 668k | { |
393 | | #ifdef DEBUG |
394 | | long recordPos = m_input->tell(); |
395 | | #endif |
396 | 668k | readU8(); |
397 | 668k | int recordType = readU8(); |
398 | 668k | if (recordType == 0 || recordType > (int)0x3f) |
399 | 1.26k | break; |
400 | 666k | auto extension = (int) readVariableLengthInteger(); |
401 | 666k | unsigned int recordLength = readVariableLengthInteger(); |
402 | 666k | const unsigned long maxLength = getRemainingLength(m_input); |
403 | 666k | if (recordLength > maxLength) |
404 | 11.1k | recordLength = static_cast<unsigned int>(maxLength); |
405 | 666k | if (recordLength > static_cast<unsigned int>(std::numeric_limits<int>::max())) |
406 | 0 | { |
407 | 0 | WPG_DEBUG_MSG(("record length %u is bigger than max int, clamping\n", recordLength)); |
408 | 0 | recordLength = std::numeric_limits<int>::max(); |
409 | 0 | } |
410 | 666k | m_recordLength = int(recordLength); |
411 | 666k | m_recordEnd = m_input->tell() + m_recordLength - 1; |
412 | | |
413 | | // inside a subgroup, one less sub record |
414 | 666k | if (!m_groupStack.empty()) |
415 | 638k | m_groupStack.top().subIndex--; |
416 | | |
417 | | // search function to handler this record |
418 | 666k | int index = -1; |
419 | 10.3M | for (int i = 0; (index < 0) && handlers[i].name; i++) |
420 | 9.68M | if (handlers[i].type == recordType) |
421 | 666k | index = i; |
422 | | |
423 | 666k | WPG_DEBUG_MSG(("\n")); |
424 | 666k | if (index < 0) |
425 | 710 | { |
426 | 710 | WPG_DEBUG_MSG(("Unknown record type 0x%02x at %li size %d extension %d\n", |
427 | 710 | recordType, recordPos, m_recordLength, extension)); |
428 | 710 | } |
429 | 666k | else |
430 | 666k | { |
431 | 666k | Method recordHandler = handlers[index].handler; |
432 | | |
433 | 666k | if (!recordHandler) |
434 | 68.8k | WPG_DEBUG_MSG(("Record '%s' (ignored) type 0x%02x at %li size %d extension %d\n", |
435 | 68.8k | handlers[index].name, recordType, recordPos, m_recordLength, extension)); |
436 | 597k | else |
437 | 597k | { |
438 | 597k | WPG_DEBUG_MSG(("Record '%s' type 0x%02x at %li size %d extension %d\n", |
439 | 597k | handlers[index].name, recordType, recordPos, m_recordLength, extension)); |
440 | | |
441 | | // invoke the handler for this record |
442 | 597k | (this->*recordHandler)(); |
443 | 597k | } |
444 | 666k | } |
445 | | |
446 | | // the last subgroup |
447 | 666k | if (!m_groupStack.empty()) |
448 | 638k | { |
449 | 638k | WPGGroupContext &context = m_groupStack.top(); |
450 | 638k | if (context.subIndex == 0) |
451 | 73.0k | { |
452 | 73.0k | if (context.isCompoundPolygon()) |
453 | 11.0k | flushCompoundPolygon(); |
454 | 73.0k | m_groupStack.pop(); |
455 | 73.0k | } |
456 | 638k | } |
457 | | |
458 | | // we enter another subgroup, save the context to stack |
459 | 666k | if (extension > 0) |
460 | 590k | { |
461 | 590k | WPGGroupContext context; |
462 | 590k | context.parentType = recordType; |
463 | 590k | context.subIndex = (unsigned int) extension; |
464 | 590k | if (context.isCompoundPolygon()) |
465 | 11.7k | { |
466 | 11.7k | context.compoundMatrix = m_compoundMatrix; |
467 | 11.7k | context.compoundFilled = m_compoundFilled; |
468 | 11.7k | context.compoundFramed = m_compoundFramed; |
469 | 11.7k | context.compoundClosed = m_compoundClosed; |
470 | 11.7k | } |
471 | 590k | m_groupStack.push(context); |
472 | 590k | } |
473 | | |
474 | | //if(m_input->tell() > m_recordEnd+1) |
475 | 666k | { |
476 | | //WPG_DEBUG_MSG(("Record 0x%x consumes more bytes than necessary!\n", recordType)); |
477 | 666k | WPG_DEBUG_MSG(("Current stream position: %li\n", m_input->tell())); |
478 | 666k | } |
479 | | |
480 | 666k | if (m_exit) break; |
481 | | |
482 | 666k | m_input->seek(m_recordEnd+1, librevenge::RVNG_SEEK_SET); |
483 | 666k | } |
484 | | |
485 | 13.3k | if (!m_exit) |
486 | 13.1k | handleEndWPG(); |
487 | | |
488 | 13.3k | return m_success; |
489 | 13.3k | } |
490 | | |
491 | | #ifdef DEBUG |
492 | | static const char *describePrecision(unsigned char precision) |
493 | | { |
494 | | const char *result = "Unknown"; |
495 | | switch (precision) |
496 | | { |
497 | | case 0: |
498 | | result = "single"; |
499 | | break; |
500 | | case 1: |
501 | | result = "double"; |
502 | | break; |
503 | | default: |
504 | | break; |
505 | | } |
506 | | return result; |
507 | | } |
508 | | |
509 | | static const char *describeGradient(unsigned char gradientType) |
510 | | { |
511 | | const char *result = "Unknown"; |
512 | | switch (gradientType) |
513 | | { |
514 | | case 0: |
515 | | result = "None"; |
516 | | break; |
517 | | case 1: |
518 | | result = "Linear"; |
519 | | break; |
520 | | case 2: |
521 | | result = "Polygonal"; |
522 | | break; |
523 | | case 3: |
524 | | result = "Concentric Circles"; |
525 | | break; |
526 | | case 4: |
527 | | result = "Convergent Circles"; |
528 | | break; |
529 | | case 5: |
530 | | result = "Concentric Ellipses"; |
531 | | break; |
532 | | case 6: |
533 | | result = "Convergent Ellipses"; |
534 | | break; |
535 | | case 7: |
536 | | result = "Concentric Squares"; |
537 | | break; |
538 | | case 8: |
539 | | result = "Convergent Squares"; |
540 | | break; |
541 | | case 9: |
542 | | result = "Concentric Rectangles"; |
543 | | break; |
544 | | case 10: |
545 | | result = "Convergent Rectangles"; |
546 | | break; |
547 | | default: |
548 | | break; |
549 | | } |
550 | | return result; |
551 | | } |
552 | | #endif |
553 | | |
554 | | void WPG2Parser::handleStartWPG() |
555 | 13.1k | { |
556 | 13.1k | if (m_graphicsStarted) // second start wpg in the document == possible corruption, bail out |
557 | 102 | { |
558 | 102 | handleEndWPG(); |
559 | 102 | return; |
560 | 102 | } |
561 | | |
562 | 13.0k | unsigned int horizontalUnit = readU16(); |
563 | 13.0k | unsigned int verticalUnit = readU16(); |
564 | 13.0k | unsigned char precision = readU8(); |
565 | | |
566 | | // sanity check |
567 | 13.0k | m_xres = horizontalUnit; |
568 | 13.0k | m_yres = verticalUnit; |
569 | 13.0k | if ((horizontalUnit==0) || (verticalUnit==0)) |
570 | 8.61k | { |
571 | 8.61k | m_xres = m_yres = 1200; |
572 | 8.61k | WPG_DEBUG_MSG(("Warning ! Insane unit of measure")); |
573 | 8.61k | } |
574 | | |
575 | | // danger if we do not recognize the precision code |
576 | 13.0k | if (precision != 0 && precision != 1) |
577 | 16 | { |
578 | 16 | m_success = false; |
579 | 16 | m_exit = true; |
580 | 16 | return; |
581 | 16 | } |
582 | 13.0k | m_doublePrecision = (precision == 1); |
583 | | |
584 | | #ifdef DEBUG |
585 | | long viewportX1 = (m_doublePrecision) ? readS32() : readS16(); |
586 | | long viewportY1 = (m_doublePrecision) ? readS32() : readS16(); |
587 | | long viewportX2 = (m_doublePrecision) ? readS32() : readS16(); |
588 | | long viewportY2 = (m_doublePrecision) ? readS32() : readS16(); |
589 | | #else |
590 | 13.0k | m_input->seek(((m_doublePrecision) ? 16 : 8), librevenge::RVNG_SEEK_CUR); |
591 | 13.0k | #endif |
592 | 13.0k | long imageX1 = (m_doublePrecision) ? readS32() : readS16(); |
593 | 13.0k | long imageY1 = (m_doublePrecision) ? readS32() : readS16(); |
594 | 13.0k | long imageX2 = (m_doublePrecision) ? readS32() : readS16(); |
595 | 13.0k | long imageY2 = (m_doublePrecision) ? readS32() : readS16(); |
596 | | |
597 | | // used to adjust coordinates |
598 | 13.0k | m_xofs = (imageX1 < imageX2) ? imageX1 : imageX2; |
599 | 13.0k | m_yofs = (imageY1 < imageY2) ? imageY1 : imageX2; |
600 | 13.0k | m_width = (imageX2 > imageX1) ? imageX2-imageX1 : imageX1-imageX2; |
601 | 13.0k | m_height = (imageY2 > imageY1) ? imageY2-imageY1 : imageY1-imageY2; |
602 | | |
603 | 13.0k | WPG_DEBUG_MSG(("StartWPG 2\n")); |
604 | 13.0k | WPG_DEBUG_MSG((" Horizontal unit of measure : %d pixels/inch\n", (int) horizontalUnit)); |
605 | 13.0k | WPG_DEBUG_MSG((" Vertical unit of measure : %d pixels/inch\n", (int) verticalUnit)); |
606 | 13.0k | WPG_DEBUG_MSG((" Data precision : %d (%s)\n", precision, describePrecision(precision))); |
607 | 13.0k | WPG_DEBUG_MSG((" Viewport X1 : %li\n", viewportX1)); |
608 | 13.0k | WPG_DEBUG_MSG((" Viewport Y1 : %li\n", viewportY1)); |
609 | 13.0k | WPG_DEBUG_MSG((" Viewport X2 : %li\n", viewportX2)); |
610 | 13.0k | WPG_DEBUG_MSG((" Viewport Y2 : %li\n", viewportY2)); |
611 | 13.0k | WPG_DEBUG_MSG((" Image X1 : %li\n", imageX1)); |
612 | 13.0k | WPG_DEBUG_MSG((" Image Y1 : %li\n", imageY1)); |
613 | 13.0k | WPG_DEBUG_MSG((" Image X2 : %li\n", imageX2)); |
614 | 13.0k | WPG_DEBUG_MSG((" Image Y2 : %li\n", imageY2)); |
615 | 13.0k | WPG_DEBUG_MSG((" X offset : %li\n", m_xofs)); |
616 | 13.0k | WPG_DEBUG_MSG((" Y offset : %li\n", m_yofs)); |
617 | 13.0k | WPG_DEBUG_MSG((" width : %li\n", m_width)); |
618 | 13.0k | WPG_DEBUG_MSG((" height : %li\n", m_height)); |
619 | | |
620 | 13.0k | librevenge::RVNGPropertyList propList; |
621 | 13.0k | propList.insert("svg:width", ((toDouble(m_width)) / m_xres)); |
622 | 13.0k | propList.insert("svg:height", ((toDouble(m_height)) / m_yres)); |
623 | | |
624 | 13.0k | m_painter->startDocument(librevenge::RVNGPropertyList()); |
625 | 13.0k | m_painter->startPage(propList); |
626 | | |
627 | 13.0k | static const int WPG2_defaultPenDashes[] = |
628 | 13.0k | { |
629 | 13.0k | 1, 291, 0, // style #0 (actually solid) |
630 | 13.0k | 1, 218, 73, // style #1 |
631 | 13.0k | 1, 145, 73, // style #2 |
632 | 13.0k | 1, 73, 73, // style #3 |
633 | 13.0k | 1, 36, 36, // style #4 |
634 | 13.0k | 1, 18, 18, // style #5 |
635 | 13.0k | 1, 18, 55, // style #6 |
636 | 13.0k | 3, 18, 55, 18, 55, 18, 127, // style #7 |
637 | 13.0k | 2, 164, 55, 18, 55, // style #8 |
638 | 13.0k | 3, 145, 36, 18, 36, 18, 36, // style #9 |
639 | 13.0k | 3, 91, 55, 91, 55, 18, 55, // style #10 |
640 | 13.0k | 4, 91, 36, 91, 36, 18, 36, 18, 36, // style #11 |
641 | 13.0k | 2, 182, 73, 73, 73, // style #12 |
642 | 13.0k | 3, 182, 36, 55, 36, 55, 36, // style #13 |
643 | 13.0k | 3, 255, 73, 266, 73, 73, 73, // style #14 |
644 | 13.0k | 4, 273, 36, 273, 36, 55, 36, 55, 36 // style #15 |
645 | 13.0k | }; |
646 | | |
647 | | // create default pen styles |
648 | 13.0k | size_t styleNo = 0; |
649 | 221k | for (size_t i = 0; i < (sizeof(WPG2_defaultPenDashes)/sizeof(WPG2_defaultPenDashes[0]));) |
650 | 208k | { |
651 | 208k | size_t segments = 2 * WPG2_defaultPenDashes[i++]; |
652 | 208k | libwpg::WPGDashArray dashArray; |
653 | 1.09M | for (size_t j = 0; j < segments; j++, i++) |
654 | 885k | dashArray.add(WPG2_defaultPenDashes[i]*3.6/218.0); |
655 | 208k | m_dashArrayStyles[styleNo] = dashArray; |
656 | 208k | styleNo++; |
657 | 208k | } |
658 | 13.0k | m_graphicsStarted = true; |
659 | 13.0k | } |
660 | | |
661 | | void WPG2Parser::handleEndWPG() |
662 | 13.8k | { |
663 | 13.8k | if (!m_graphicsStarted) |
664 | 787 | return; |
665 | | // sentinel |
666 | 13.0k | if (m_layerOpened) |
667 | 87 | m_painter->endLayer(); |
668 | | |
669 | 13.0k | m_painter->endPage(); |
670 | 13.0k | m_painter->endDocument(); |
671 | 13.0k | m_exit = true; |
672 | 13.0k | } |
673 | | |
674 | | void WPG2Parser::handleFormSettings() |
675 | 1.57k | { |
676 | | #ifdef DEBUG |
677 | | unsigned int w = (m_doublePrecision) ? readU32() : readU16(); |
678 | | unsigned int h = (m_doublePrecision) ? readU32() : readU16(); |
679 | | double width = (toDouble(w)) / m_xres; |
680 | | double height = (toDouble(h)) / m_yres; |
681 | | m_input->seek(((m_doublePrecision) ? 4 : 2), librevenge::RVNG_SEEK_CUR); |
682 | | unsigned int ml = (m_doublePrecision) ? readU32() : readU16(); |
683 | | unsigned int mr = (m_doublePrecision) ? readU32() : readU16(); |
684 | | unsigned int mt = (m_doublePrecision) ? readU32() : readU16(); |
685 | | unsigned int mb = (m_doublePrecision) ? readU32() : readU16(); |
686 | | double margL = (toDouble(ml)) / m_xres; |
687 | | double margR = (toDouble(mr)) / m_xres; |
688 | | double margT = (toDouble(mt)) / m_xres; |
689 | | double margB = (toDouble(mb)) / m_xres; |
690 | | |
691 | | WPG_DEBUG_MSG(("Form Settings: width: %f height : %f\n", width, height)); |
692 | | WPG_DEBUG_MSG(("Form Margins: left: %f right : %f top: %f bottom: %f\n", margL, margR, margT, margB)); |
693 | | #endif |
694 | 1.57k | } |
695 | | |
696 | | void WPG2Parser::handleLayer() |
697 | 259k | { |
698 | 259k | if (!m_graphicsStarted) |
699 | 221 | return; |
700 | 259k | librevenge::RVNGPropertyList propList; |
701 | 259k | propList.insert("svg:id", (int)readU16()); |
702 | | |
703 | | // close previous one |
704 | 259k | if (m_layerOpened) |
705 | 259k | m_painter->endLayer(); |
706 | | |
707 | 259k | m_painter->startLayer(propList); |
708 | 259k | m_layerOpened = true; |
709 | | |
710 | 259k | WPG_DEBUG_MSG((" Layer Id: %d\n", (int) m_layerId)); |
711 | 259k | } |
712 | | |
713 | | void WPG2Parser::handleCompoundPolygon() |
714 | 13.8k | { |
715 | 13.8k | if (!m_graphicsStarted) |
716 | 706 | return; |
717 | 13.1k | ObjectCharacterization objCh; |
718 | 13.1k | parseCharacterization(&objCh); |
719 | | |
720 | 13.1k | m_compoundWindingRule = objCh.windingRule; |
721 | 13.1k | m_compoundMatrix = objCh.matrix; |
722 | 13.1k | m_compoundFilled = objCh.filled; |
723 | 13.1k | m_compoundFramed = objCh.framed; |
724 | 13.1k | m_compoundClosed = objCh.closed; |
725 | 13.1k | } |
726 | | |
727 | | void WPG2Parser::flushCompoundPolygon() |
728 | 11.0k | { |
729 | 11.0k | if (!m_graphicsStarted) |
730 | 535 | return; |
731 | 10.5k | WPGGroupContext &context = m_groupStack.top(); |
732 | | |
733 | 10.5k | librevenge::RVNGPropertyList tmpStyle = m_style; |
734 | | |
735 | 10.5k | if (!context.compoundFilled) |
736 | 8.36k | tmpStyle.insert("draw:fill", "none"); |
737 | 10.5k | if (!context.compoundFramed) |
738 | 6.95k | tmpStyle.insert("draw:stroke", "none"); |
739 | | |
740 | 10.5k | if (context.compoundWindingRule) |
741 | 0 | tmpStyle.insert("svg:fill-rule", "nonzero"); |
742 | 10.5k | else |
743 | 10.5k | tmpStyle.insert("svg:fill-rule", "evenodd"); |
744 | | |
745 | 10.5k | if (context.compoundFilled || m_gradient.count()) |
746 | 2.48k | tmpStyle.insert("svg:linearGradient", m_gradient); |
747 | 10.5k | m_painter->setStyle(tmpStyle); |
748 | | |
749 | 10.5k | if (context.compoundClosed) |
750 | 238 | { |
751 | 238 | librevenge::RVNGPropertyList element; |
752 | 238 | element.insert("librevenge:path-action", "Z"); |
753 | 238 | context.compoundPath.append(element); |
754 | 238 | } |
755 | 10.5k | librevenge::RVNGPropertyList propList; |
756 | 10.5k | propList.insert("svg:d", context.compoundPath); |
757 | 10.5k | m_painter->drawPath(propList); |
758 | 10.5k | } |
759 | | |
760 | | void WPG2Parser::handlePenStyleDefinition() |
761 | 34.2k | { |
762 | 34.2k | if (!m_graphicsStarted) |
763 | 390 | return; |
764 | 33.8k | unsigned int style = readU16(); |
765 | 33.8k | unsigned int segments = readU16(); |
766 | | |
767 | 33.8k | const unsigned int maxSegments = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 2; |
768 | 33.8k | if (segments > maxSegments) |
769 | 31.9k | segments = maxSegments; |
770 | | |
771 | 33.8k | libwpg::WPGDashArray dashArray; |
772 | 487k | for (unsigned i = 0; i < segments; i++) |
773 | 453k | { |
774 | 453k | unsigned int p = (m_doublePrecision) ? readU32() : readU16(); |
775 | 453k | unsigned int q = (m_doublePrecision) ? readU32() : readU16(); |
776 | 453k | dashArray.add(toDouble(p)*3.6/218.0); |
777 | 453k | dashArray.add(toDouble(q)*3.6/218.0); |
778 | 453k | } |
779 | 33.8k | m_dashArrayStyles[style] = dashArray; |
780 | | |
781 | 33.8k | WPG_DEBUG_MSG((" Style : %d\n", (int) style)); |
782 | 33.8k | WPG_DEBUG_MSG((" Segment pairs : %d\n", (int) segments)); |
783 | 33.8k | } |
784 | | |
785 | | // TODO |
786 | | void WPG2Parser::handlePatternDefinition() |
787 | 1.12k | { |
788 | 1.12k | if (!m_graphicsStarted) |
789 | 1 | return; |
790 | 1.12k | WPG_DEBUG_MSG(("PatternDefinition\n")); |
791 | 1.12k | } |
792 | | |
793 | | void WPG2Parser::handleColorPalette() |
794 | 617 | { |
795 | 617 | if (!m_graphicsStarted) |
796 | 205 | return; |
797 | 412 | unsigned startIndex = readU16(); |
798 | 412 | unsigned numEntries = readU16(); |
799 | | |
800 | 1.95M | for (unsigned i = 0; i < numEntries; i++) |
801 | 1.95M | { |
802 | 1.95M | unsigned char red = readU8(); |
803 | 1.95M | unsigned char green = readU8(); |
804 | 1.95M | unsigned char blue = readU8(); |
805 | 1.95M | unsigned char alpha = 0xff - readU8(); |
806 | 1.95M | libwpg::WPGColor color(red, green, blue, alpha); |
807 | 1.95M | m_colorPalette[int(startIndex+i)] = color; |
808 | 1.95M | WPG_DEBUG_MSG(("Index#%d: RGB %s\n", startIndex+i, color.getColorString().cstr())); |
809 | 1.95M | } |
810 | 412 | } |
811 | | |
812 | | void WPG2Parser::handleDPColorPalette() |
813 | 11.1k | { |
814 | 11.1k | if (!m_graphicsStarted) |
815 | 196 | return; |
816 | 10.9k | unsigned startIndex = readU16(); |
817 | 10.9k | unsigned numEntries = readU16(); |
818 | | |
819 | 2.10M | for (unsigned int i = 0; i < numEntries; i++) |
820 | 2.09M | { |
821 | 2.09M | unsigned char red = readU16() >> 8 ; |
822 | 2.09M | unsigned char green = readU16() >> 8 ; |
823 | 2.09M | unsigned char blue = readU16() >> 8 ; |
824 | 2.09M | unsigned char alpha = 0xff - (readU16() >> 8) ; |
825 | 2.09M | libwpg::WPGColor color(red, green, blue, alpha); |
826 | 2.09M | m_colorPalette[int(startIndex+i)] = color; |
827 | 2.09M | WPG_DEBUG_MSG(("Index#%d: RGB %s\n", startIndex+i, color.getColorString().cstr())); |
828 | 2.09M | } |
829 | 10.9k | } |
830 | | |
831 | | void WPG2Parser::handlePenForeColor() |
832 | 889 | { |
833 | 889 | if (!m_graphicsStarted) |
834 | 219 | return; |
835 | 670 | if (!m_groupStack.empty()) |
836 | 469 | { |
837 | 469 | if (m_groupStack.top().isCompoundPolygon()) |
838 | 66 | return; |
839 | 403 | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
840 | 129 | return; |
841 | 403 | } |
842 | 475 | unsigned char red = readU8(); |
843 | 475 | unsigned char green = readU8(); |
844 | 475 | unsigned char blue = readU8(); |
845 | 475 | unsigned char alpha = 0xff - readU8(); |
846 | | |
847 | 475 | m_penForeColor = libwpg::WPGColor(red, green, blue, alpha); |
848 | | |
849 | 475 | m_style.insert("svg:stroke-color", m_penForeColor.getColorString()); |
850 | 475 | m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
851 | | |
852 | 475 | WPG_DEBUG_MSG((" Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
853 | 475 | } |
854 | | |
855 | | void WPG2Parser::handleDPPenForeColor() |
856 | 1.34k | { |
857 | 1.34k | if (!m_graphicsStarted) |
858 | 209 | return; |
859 | 1.13k | if (!m_groupStack.empty()) |
860 | 788 | { |
861 | 788 | if (m_groupStack.top().isCompoundPolygon()) |
862 | 69 | return; |
863 | 719 | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
864 | 117 | return; |
865 | 719 | } |
866 | | // we just ignore the least significant 8 bits |
867 | 947 | unsigned char red = (m_doublePrecision) ? readU16()>>8 : readU8(); |
868 | 947 | unsigned char green = (m_doublePrecision) ? readU16()>>8 : readU8(); |
869 | 947 | unsigned char blue = (m_doublePrecision) ? readU16()>>8 : readU8(); |
870 | 947 | unsigned char alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8()); |
871 | | |
872 | 947 | m_penForeColor = libwpg::WPGColor(red, green, blue, alpha); |
873 | | |
874 | 947 | m_style.insert("svg:stroke-color", m_penForeColor.getColorString()); |
875 | 947 | m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
876 | | |
877 | 947 | WPG_DEBUG_MSG((" Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
878 | 947 | } |
879 | | |
880 | | void WPG2Parser::handlePenBackColor() |
881 | 6.09k | { |
882 | 6.09k | if (!m_graphicsStarted) |
883 | 232 | return; |
884 | 5.86k | if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon()) |
885 | 573 | return; |
886 | | |
887 | 5.29k | unsigned char red = readU8(); |
888 | 5.29k | unsigned char green = readU8(); |
889 | 5.29k | unsigned char blue = readU8(); |
890 | 5.29k | unsigned char alpha = 0xff - readU8(); |
891 | | |
892 | 5.29k | m_penBackColor = libwpg::WPGColor(red, green, blue, alpha); |
893 | | |
894 | 5.29k | m_style.insert("svg:stroke-color", m_penForeColor.getColorString()); |
895 | 5.29k | m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
896 | | |
897 | 5.29k | WPG_DEBUG_MSG((" Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
898 | 5.29k | } |
899 | | |
900 | | void WPG2Parser::handleDPPenBackColor() |
901 | 3.43k | { |
902 | 3.43k | if (!m_graphicsStarted) |
903 | 311 | return; |
904 | 3.11k | if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon()) |
905 | 2.40k | return; |
906 | | |
907 | | // we just ignore the least significant 8 bits |
908 | 710 | unsigned int red = (m_doublePrecision) ? readU16()>>8 : readU8(); |
909 | 710 | unsigned int green = (m_doublePrecision) ? readU16()>>8 : readU8(); |
910 | 710 | unsigned int blue = (m_doublePrecision) ? readU16()>>8 : readU8(); |
911 | 710 | unsigned int alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8()); |
912 | | |
913 | 710 | m_penBackColor = libwpg::WPGColor((int) red, (int) green, (int) blue, (int) alpha); |
914 | | |
915 | 710 | m_style.insert("svg:stroke-color", m_penForeColor.getColorString()); |
916 | 710 | m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
917 | | |
918 | 710 | WPG_DEBUG_MSG((" Background color (RGBA): %d %d %d %d\n", (int) red, (int) green, (int) blue, (int) alpha)); |
919 | 710 | } |
920 | | |
921 | | void WPG2Parser::setPenStyle() |
922 | 36.0k | { |
923 | 36.0k | if (!m_style["draw:stroke"] || m_style["draw:stroke"]->getStr() != "dash") |
924 | 22.8k | return; |
925 | 13.1k | { |
926 | 13.1k | double strokeWidth = m_style["svg:stroke-width"] ? m_style["svg:stroke-width"]->getDouble() : 0.0; |
927 | 13.1k | m_style.insert("draw:dots1", m_dashArray.getDots1()); |
928 | 13.1k | m_style.insert("draw:dots1-length", 72.0*72.0*strokeWidth*(m_dashArray.getDots1Length()), librevenge::RVNG_POINT); |
929 | 13.1k | m_style.insert("draw:dots2", m_dashArray.getDots2()); |
930 | 13.1k | m_style.insert("draw:dots2-length", 72.0*72.0*strokeWidth*(m_dashArray.getDots2Length()), librevenge::RVNG_POINT); |
931 | 13.1k | m_style.insert("draw:distance", 72.0*72.0*strokeWidth*(m_dashArray.getDistance()), librevenge::RVNG_POINT); |
932 | 13.1k | } |
933 | 13.1k | } |
934 | | |
935 | | void WPG2Parser::handlePenStyle() |
936 | 37.8k | { |
937 | 37.8k | if (!m_graphicsStarted) |
938 | 283 | return; |
939 | 37.5k | if (!m_groupStack.empty()) |
940 | 37.3k | { |
941 | 37.3k | if (m_groupStack.top().isCompoundPolygon()) |
942 | 1.01k | return; |
943 | 36.2k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
944 | 461 | return; |
945 | 36.2k | } |
946 | 36.0k | unsigned int style = readU16(); |
947 | | |
948 | 36.0k | m_dashArray = m_dashArrayStyles[style]; |
949 | | |
950 | 36.0k | if (!m_dashArray.getDots1() || !m_dashArray.getDots2()) |
951 | 22.8k | m_style.insert("draw:stroke", "solid"); |
952 | 13.1k | else |
953 | 13.1k | m_style.insert("draw:stroke", "dash"); |
954 | | |
955 | 36.0k | setPenStyle(); |
956 | | |
957 | 36.0k | WPG_DEBUG_MSG((" Pen style : %d\n", (int) style)); |
958 | 36.0k | } |
959 | | |
960 | | void WPG2Parser::handlePenSize() |
961 | 9.09k | { |
962 | 9.09k | if (!m_graphicsStarted) |
963 | 225 | return; |
964 | 8.87k | if (!m_groupStack.empty()) |
965 | 8.69k | { |
966 | 8.69k | if (m_groupStack.top().isCompoundPolygon()) |
967 | 423 | return; |
968 | 8.27k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
969 | 147 | return; |
970 | 8.27k | } |
971 | 8.30k | unsigned int width = readU16(); |
972 | | |
973 | 8.30k | m_style.insert("svg:stroke-width", (toDouble(width) / m_xres)); |
974 | | |
975 | 8.30k | WPG_DEBUG_MSG((" Width: %d\n", (int) width)); |
976 | 8.30k | } |
977 | | |
978 | | void WPG2Parser::handleDPPenSize() |
979 | 9.32k | { |
980 | 9.32k | if (!m_graphicsStarted) |
981 | 279 | return; |
982 | 9.04k | if (!m_groupStack.empty()) |
983 | 8.45k | { |
984 | 8.45k | if (m_groupStack.top().isCompoundPolygon()) |
985 | 230 | return; |
986 | 8.22k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
987 | 138 | return; |
988 | 8.22k | } |
989 | 8.67k | unsigned long width = readU32(); |
990 | | |
991 | 8.67k | m_style.insert("svg:stroke-width", toDouble(width) / m_xres / 256); |
992 | | // m_pen.height = toDouble(height) / m_yres / 256; |
993 | | |
994 | 8.67k | WPG_DEBUG_MSG((" Width: %li\n", (long) width)); |
995 | 8.67k | } |
996 | | |
997 | | void WPG2Parser::handleLineCap() |
998 | 306 | { |
999 | 306 | if (!m_graphicsStarted) |
1000 | 135 | return; |
1001 | 171 | if (!m_groupStack.empty()) |
1002 | 169 | { |
1003 | 169 | if (m_groupStack.top().isCompoundPolygon()) |
1004 | 1 | return; |
1005 | 168 | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1006 | 9 | return; |
1007 | 168 | } |
1008 | | // WPG_DEBUG_MSG((" Line cap : %d\n", style)); |
1009 | 171 | } |
1010 | | |
1011 | | void WPG2Parser::handleLineJoin() |
1012 | 274 | { |
1013 | 274 | if (!m_graphicsStarted) |
1014 | 255 | return; |
1015 | 19 | if (!m_groupStack.empty()) |
1016 | 19 | { |
1017 | 19 | if (m_groupStack.top().isCompoundPolygon()) |
1018 | 0 | return; |
1019 | 19 | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1020 | 4 | return; |
1021 | 19 | } |
1022 | | // WPG_DEBUG_MSG((" Line join : %d\n", style)); |
1023 | 19 | } |
1024 | | |
1025 | | void WPG2Parser::handleBrushGradient() |
1026 | 2.77k | { |
1027 | 2.77k | if (!m_graphicsStarted) |
1028 | 365 | return; |
1029 | 2.41k | if (!m_groupStack.empty()) |
1030 | 1.90k | { |
1031 | 1.90k | if (m_groupStack.top().isCompoundPolygon()) |
1032 | 341 | return; |
1033 | 1.56k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1034 | 388 | return; |
1035 | 1.56k | } |
1036 | 1.68k | unsigned angleFraction = readU16(); |
1037 | 1.68k | unsigned angleInteger = readU16(); |
1038 | 1.68k | unsigned xref = readU16(); |
1039 | 1.68k | unsigned yref = readU16(); |
1040 | | #ifdef DEBUG |
1041 | | unsigned flag = readU16(); |
1042 | | bool granular = flag & (1<<6); |
1043 | | bool anchor = flag & (1<<7); |
1044 | | #else |
1045 | 1.68k | readU16(); |
1046 | 1.68k | #endif |
1047 | | |
1048 | | // TODO: get gradient extent |
1049 | | |
1050 | 1.68k | m_gradientAngle = angleInteger + (double)angleFraction/65536.0; |
1051 | 1.68k | m_gradientRef.insert("svg:cx", (double)xref); |
1052 | 1.68k | m_gradientRef.insert("svg:cy", (double)yref); |
1053 | | |
1054 | 1.68k | WPG_DEBUG_MSG((" Gradient angle : %d.%d\n", (int) angleInteger, (int) angleFraction)); |
1055 | 1.68k | WPG_DEBUG_MSG((" Gradient reference : %d.%d\n", (int) xref, (int) yref)); |
1056 | 1.68k | WPG_DEBUG_MSG((" Granular : %s\n", (granular ? "yes" : "no"))); |
1057 | 1.68k | WPG_DEBUG_MSG((" Anchored : %s\n", (anchor ? "yes" : "no"))); |
1058 | 1.68k | } |
1059 | | |
1060 | | void WPG2Parser::handleDPBrushGradient() |
1061 | 6.86k | { |
1062 | 6.86k | if (!m_graphicsStarted) |
1063 | 511 | return; |
1064 | 6.35k | if (!m_groupStack.empty()) |
1065 | 5.29k | { |
1066 | 5.29k | if (m_groupStack.top().isCompoundPolygon()) |
1067 | 716 | return; |
1068 | 4.58k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1069 | 717 | return; |
1070 | 4.58k | } |
1071 | 4.92k | unsigned angleFraction = readU16(); |
1072 | 4.92k | unsigned angleInteger = readU16(); |
1073 | 4.92k | unsigned xref = readU16(); |
1074 | 4.92k | unsigned yref = readU16(); |
1075 | | #ifdef DEBUG |
1076 | | unsigned flag = readU16(); |
1077 | | bool granular = flag & (1<<6); |
1078 | | bool anchor = flag & (1<<7); |
1079 | | #else |
1080 | 4.92k | readU16(); |
1081 | 4.92k | #endif |
1082 | | |
1083 | | // TODO: get gradient extent (in double precision) |
1084 | | |
1085 | 4.92k | m_gradientAngle = angleFraction + (double)angleInteger/65536.0; |
1086 | 4.92k | m_gradientRef.insert("svg:cx", (double)xref); |
1087 | 4.92k | m_gradientRef.insert("svg:cy", (double)yref); |
1088 | | |
1089 | 4.92k | WPG_DEBUG_MSG((" Gradient angle : %d.%d\n", (int) angleInteger, (int) angleFraction)); |
1090 | 4.92k | WPG_DEBUG_MSG((" Gradient reference : %d.%d\n", (int) xref, (int) yref)); |
1091 | 4.92k | WPG_DEBUG_MSG((" Granular : %s\n", (granular ? "yes" : "no"))); |
1092 | 4.92k | WPG_DEBUG_MSG((" Anchored : %s\n", (anchor ? "yes" : "no"))); |
1093 | 4.92k | } |
1094 | | |
1095 | | void WPG2Parser::handleBrushForeColor() |
1096 | 11.7k | { |
1097 | 11.7k | if (!m_graphicsStarted) |
1098 | 1.24k | return; |
1099 | 10.5k | if (!m_groupStack.empty()) |
1100 | 8.76k | { |
1101 | 8.76k | if (m_groupStack.top().isCompoundPolygon()) |
1102 | 1.53k | return; |
1103 | 7.22k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1104 | 1.48k | return; |
1105 | 7.22k | } |
1106 | 7.53k | unsigned char gradientType = readU8(); |
1107 | 7.53k | WPG_DEBUG_MSG((" Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType))); |
1108 | | |
1109 | 7.53k | if (gradientType == 0) |
1110 | 5.43k | { |
1111 | 5.43k | unsigned char red = readU8(); |
1112 | 5.43k | unsigned char green = readU8(); |
1113 | 5.43k | unsigned char blue = readU8(); |
1114 | 5.43k | unsigned char alpha = 0xff - readU8(); |
1115 | 5.43k | WPG_DEBUG_MSG((" Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
1116 | | |
1117 | 5.43k | m_brushForeColor = libwpg::WPGColor(red, green, blue, alpha); |
1118 | | |
1119 | 5.43k | m_style.insert("draw:fill-color", m_brushForeColor.getColorString()); |
1120 | 5.43k | m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
1121 | | |
1122 | 5.43k | if (!m_style["draw:fill"] || m_style["draw:fill"]->getStr() != "gradient") |
1123 | 5.18k | m_style.insert("draw:fill", "solid"); |
1124 | 5.43k | } |
1125 | 2.09k | else |
1126 | 2.09k | { |
1127 | 2.09k | unsigned count = readU16(); |
1128 | 2.09k | std::vector<libwpg::WPGColor> colors; |
1129 | 2.09k | std::vector<double> positions; |
1130 | 2.09k | WPG_DEBUG_MSG((" Gradient colors : %d\n", (int) count)); |
1131 | | |
1132 | 2.09k | if (count > 0) |
1133 | 2.04k | { |
1134 | 9.11M | for (unsigned i = 0; i < count; i++) |
1135 | 9.11M | { |
1136 | 9.11M | unsigned char red = readU8(); |
1137 | 9.11M | unsigned char green = readU8(); |
1138 | 9.11M | unsigned char blue = readU8(); |
1139 | 9.11M | unsigned char alpha = 0xff - readU8(); |
1140 | 9.11M | libwpg::WPGColor color(red, green, blue, alpha); |
1141 | 9.11M | colors.push_back(color); |
1142 | 9.11M | WPG_DEBUG_MSG((" Color #%d (RGBA): %d %d %d %d\n", i+1, red, green, blue, alpha)); |
1143 | 9.11M | } |
1144 | | |
1145 | 9.11M | for (unsigned j = 0; j < count-1; j++) |
1146 | 9.11M | { |
1147 | 9.11M | unsigned pos = readU16(); |
1148 | 9.11M | positions.push_back(toDouble(pos)); |
1149 | 9.11M | WPG_DEBUG_MSG((" Position #%d : %d\n", j+1, (int) pos)); |
1150 | 9.11M | } |
1151 | 2.04k | } |
1152 | | |
1153 | | // looks like Corel Presentations only create 2 colors gradient |
1154 | | // and they are actually in reverse order |
1155 | 2.09k | if (count == 2) |
1156 | 717 | { |
1157 | 717 | const int cx = m_gradientRef["svg:cx"] ? m_gradientRef["svg:cx"]->getInt() : 65535; |
1158 | 717 | const int cy = m_gradientRef["svg:cy"] ? m_gradientRef["svg:cy"]->getInt() : 65535; |
1159 | 717 | double xref = double(cx) / 65536.0; |
1160 | 717 | double yref = double(cy) / 65536.0; |
1161 | 717 | double angle = m_gradientAngle*M_PI/180.0; |
1162 | 717 | double tanangle = tan(angle); |
1163 | 717 | double ref = (tanangle < 1e2 && tanangle > -1e2) ? (yref+xref*tanangle)/(1+tanangle) : xref; |
1164 | 717 | librevenge::RVNGPropertyListVector gradient; |
1165 | 717 | m_style.insert("draw:angle", (int)(-m_gradientAngle)); // upside down |
1166 | 717 | librevenge::RVNGPropertyList propList; |
1167 | 717 | propList.insert("svg:offset", 0.0, librevenge::RVNG_PERCENT); |
1168 | 717 | propList.insert("svg:stop-color", colors[1].getColorString()); |
1169 | 717 | propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT); |
1170 | 717 | gradient.append(propList); |
1171 | 717 | propList.clear(); |
1172 | 717 | propList.insert("svg:offset", ref, librevenge::RVNG_PERCENT); |
1173 | 717 | propList.insert("svg:stop-color", colors[0].getColorString()); |
1174 | 717 | propList.insert("svg:stop-opacity", colors[0].getOpacity(), librevenge::RVNG_PERCENT); |
1175 | 717 | gradient.append(propList); |
1176 | 717 | propList.clear(); |
1177 | 717 | if ((cx != 65535) && (cy != 65535)) |
1178 | 341 | { |
1179 | 341 | propList.insert("svg:offset", 1.0, librevenge::RVNG_PERCENT); |
1180 | 341 | propList.insert("svg:stop-color", colors[1].getColorString()); |
1181 | 341 | propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT); |
1182 | 341 | gradient.append(propList); |
1183 | 341 | } |
1184 | 717 | m_gradient = gradient; |
1185 | 717 | m_style.insert("draw:fill", "gradient"); |
1186 | 717 | } |
1187 | 2.09k | } |
1188 | 7.53k | } |
1189 | | |
1190 | | void WPG2Parser::handleDPBrushForeColor() |
1191 | 6.48k | { |
1192 | 6.48k | if (!m_graphicsStarted) |
1193 | 759 | return; |
1194 | 5.72k | if (!m_groupStack.empty()) |
1195 | 4.86k | { |
1196 | 4.86k | if (m_groupStack.top().isCompoundPolygon()) |
1197 | 626 | return; |
1198 | 4.24k | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1199 | 847 | return; |
1200 | 4.24k | } |
1201 | 4.25k | unsigned char gradientType = readU8(); |
1202 | 4.25k | WPG_DEBUG_MSG((" Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType))); |
1203 | | |
1204 | 4.25k | if (gradientType == 0) |
1205 | 2.74k | { |
1206 | 2.74k | unsigned char red = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1207 | 2.74k | unsigned char green = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1208 | 2.74k | unsigned char blue = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1209 | 2.74k | unsigned char alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8()); |
1210 | 2.74k | WPG_DEBUG_MSG((" Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
1211 | | |
1212 | 2.74k | m_brushForeColor = libwpg::WPGColor(red, green, blue, alpha); |
1213 | | |
1214 | 2.74k | m_style.insert("draw:fill-color", m_brushForeColor.getColorString()); |
1215 | 2.74k | m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
1216 | | |
1217 | 2.74k | if (!m_style["draw:fill"] || m_style["draw:fill"]->getStr() != "none") |
1218 | 2.74k | m_style.insert("draw:fill", "solid"); |
1219 | 2.74k | } |
1220 | 1.50k | else |
1221 | 1.50k | { |
1222 | 1.50k | unsigned count = readU16(); |
1223 | 1.50k | std::vector<libwpg::WPGColor> colors; |
1224 | 1.50k | std::vector<double> positions; |
1225 | 1.50k | WPG_DEBUG_MSG((" Gradient colors : %d\n", (int) count)); |
1226 | | |
1227 | 1.50k | if (count > 0) |
1228 | 1.39k | { |
1229 | 2.36M | for (unsigned i = 0; i < count; i++) |
1230 | 2.36M | { |
1231 | 2.36M | unsigned char red = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1232 | 2.36M | unsigned char green = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1233 | 2.36M | unsigned char blue = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1234 | 2.36M | unsigned char alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8()); |
1235 | 2.36M | libwpg::WPGColor color(red, green, blue, alpha); |
1236 | 2.36M | colors.push_back(color); |
1237 | 2.36M | WPG_DEBUG_MSG((" Color #%d (RGBA): %d %d %d %d\n", i+1, red, green, blue, alpha)); |
1238 | 2.36M | } |
1239 | | |
1240 | 2.36M | for (unsigned j = 0; j < count-1; j++) |
1241 | 2.36M | { |
1242 | 2.36M | unsigned pos = readU16(); |
1243 | 2.36M | positions.push_back(toDouble(pos)); |
1244 | 2.36M | WPG_DEBUG_MSG((" Position #%d : %d\n", j+1, (int) pos)); |
1245 | 2.36M | } |
1246 | 1.39k | } |
1247 | | |
1248 | | // looks like Corel Presentations only create 2 colors gradient |
1249 | | // and they are actually in reverse order |
1250 | 1.50k | if (count == 2) |
1251 | 905 | { |
1252 | 905 | const int cx = m_gradientRef["svg:cx"] ? m_gradientRef["svg:cx"]->getInt() : 65535; |
1253 | 905 | const int cy = m_gradientRef["svg:cy"] ? m_gradientRef["svg:cy"]->getInt() : 65535; |
1254 | 905 | const double xref = double(cx)/65536.0; |
1255 | 905 | const double yref = double(cy)/65536.0; |
1256 | 905 | double angle = m_gradientAngle*M_PI/180.0; |
1257 | 905 | double tanangle = tan(angle); |
1258 | 905 | double ref = (tanangle<1e2) ? (yref+xref*tanangle)/(1+tanangle) : xref; |
1259 | 905 | librevenge::RVNGPropertyListVector gradient; |
1260 | 905 | m_style.insert("draw:angle", (int)(-m_gradientAngle)); |
1261 | | |
1262 | 905 | librevenge::RVNGPropertyList propList; |
1263 | 905 | propList.insert("svg:offset", 0.0, librevenge::RVNG_PERCENT); |
1264 | 905 | propList.insert("svg:stop-color", colors[1].getColorString()); |
1265 | 905 | propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT); |
1266 | 905 | gradient.append(propList); |
1267 | 905 | propList.clear(); |
1268 | 905 | propList.insert("svg:offset", ref, librevenge::RVNG_PERCENT); |
1269 | 905 | propList.insert("svg:stop-color", colors[0].getColorString()); |
1270 | 905 | propList.insert("svg:stop-opacity", colors[0].getOpacity(), librevenge::RVNG_PERCENT); |
1271 | 905 | gradient.append(propList); |
1272 | 905 | propList.clear(); |
1273 | 905 | if ((cx != 65535) && (cy != 65535)) |
1274 | 413 | { |
1275 | 413 | propList.insert("svg:offset", 1.0, librevenge::RVNG_PERCENT); |
1276 | 413 | propList.insert("svg:stop-color", colors[1].getColorString()); |
1277 | 413 | propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT); |
1278 | 413 | gradient.append(propList); |
1279 | 413 | } |
1280 | 905 | m_gradient = gradient; |
1281 | 905 | } |
1282 | 1.50k | m_style.insert("draw:fill", "gradient"); |
1283 | 1.50k | } |
1284 | 4.25k | } |
1285 | | |
1286 | | void WPG2Parser::handleBrushBackColor() |
1287 | 578 | { |
1288 | 578 | if (!m_graphicsStarted) |
1289 | 229 | return; |
1290 | 349 | if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon()) |
1291 | 5 | return; |
1292 | 344 | unsigned char red = readU8(); |
1293 | 344 | unsigned char green = readU8(); |
1294 | 344 | unsigned char blue = readU8(); |
1295 | 344 | unsigned char alpha = 0xff - readU8(); |
1296 | | |
1297 | 344 | m_brushBackColor = libwpg::WPGColor(red, green, blue, alpha); |
1298 | | |
1299 | 344 | m_style.insert("draw:fill-color", m_brushForeColor.getColorString()); |
1300 | 344 | m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
1301 | | |
1302 | 344 | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none") |
1303 | 0 | m_style.insert("draw:fill", "solid"); |
1304 | | |
1305 | 344 | WPG_DEBUG_MSG((" Backround color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
1306 | 344 | } |
1307 | | |
1308 | | void WPG2Parser::handleDPBrushBackColor() |
1309 | 879 | { |
1310 | 879 | if (!m_graphicsStarted) |
1311 | 321 | return; |
1312 | 558 | if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon()) |
1313 | 10 | return; |
1314 | | // we just ignore the least significant 8 bits |
1315 | 548 | unsigned int red = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1316 | 548 | unsigned int green = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1317 | 548 | unsigned int blue = (m_doublePrecision) ? readU16()>>8 : readU8(); |
1318 | 548 | unsigned int alpha = 0xff - (m_doublePrecision) ? readU16()>>8 : readU8(); |
1319 | | |
1320 | 548 | m_brushBackColor = libwpg::WPGColor(red, green, blue, alpha); |
1321 | | |
1322 | 548 | m_style.insert("draw:fill-color", m_brushForeColor.getColorString()); |
1323 | 548 | m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT); |
1324 | | |
1325 | 548 | if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none") |
1326 | 0 | m_style.insert("draw:fill", "solid"); |
1327 | | |
1328 | 548 | WPG_DEBUG_MSG((" Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha)); |
1329 | 548 | } |
1330 | | |
1331 | | void WPG2Parser::handleBrushPattern() |
1332 | 329 | { |
1333 | 329 | if (!m_graphicsStarted) |
1334 | 10 | return; |
1335 | 319 | if (!m_groupStack.empty()) |
1336 | 312 | { |
1337 | 312 | if (m_groupStack.top().isCompoundPolygon()) |
1338 | 3 | return; |
1339 | 309 | if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now |
1340 | 21 | return; |
1341 | 309 | } |
1342 | | #ifdef DEBUG |
1343 | | unsigned int pattern = readU16(); |
1344 | | #endif |
1345 | | |
1346 | | // TODO |
1347 | | |
1348 | 295 | WPG_DEBUG_MSG((" Pattern : %d\n", (int) pattern)); |
1349 | 295 | } |
1350 | | |
1351 | | void WPG2Parser::parseCharacterization(ObjectCharacterization *ch) |
1352 | 123k | { |
1353 | | // sanity check |
1354 | 123k | if (!ch) return; |
1355 | | |
1356 | | // identity |
1357 | 123k | ch->matrix = WPG2TransformMatrix(); |
1358 | | |
1359 | 123k | unsigned int flags = readU16(); |
1360 | 123k | ch->taper = (flags & 0x01) != 0; |
1361 | 123k | ch->translate = (flags & 0x02) != 0; |
1362 | 123k | ch->skew = (flags & 0x04) != 0; |
1363 | 123k | ch->scale = (flags & 0x08) != 0; |
1364 | 123k | ch->rotate = (flags & 0x10) != 0; |
1365 | 123k | ch->hasObjectId = (flags & 0x20) != 0; |
1366 | 123k | ch->editLock = (flags & 0x80) != 0; |
1367 | 123k | ch->windingRule = (flags & (1<<12)) != 0; |
1368 | 123k | ch->filled = (flags & (1<<13)) != 0; |
1369 | 123k | ch->closed = (flags & (1<<14)) != 0; |
1370 | 123k | ch->framed = (flags & (1<<15)) != 0; |
1371 | | |
1372 | 123k | if (ch->editLock) ch->lockFlags = readU32(); |
1373 | | |
1374 | | // object ID can be 2 or 4 bytes |
1375 | 123k | if (ch->hasObjectId) ch->objectId = readU16(); |
1376 | 123k | if (ch->objectId >> 15) ch->objectId = ((ch->objectId & 0x7fff) << 16) | readU16(); |
1377 | | |
1378 | 123k | if (ch->rotate) ch->rotationAngle = fixedPointToDouble(readU32()); |
1379 | | |
1380 | 123k | if (ch->rotate || ch->scale) |
1381 | 59.8k | { |
1382 | 59.8k | ch->sxcos = readS32(); |
1383 | 59.8k | ch->sycos = readS32(); |
1384 | 59.8k | ch->matrix.element[0][0] = (double)(ch->sxcos)/65536; |
1385 | 59.8k | ch->matrix.element[1][1] = (double)(ch->sxcos)/65536; |
1386 | 59.8k | } |
1387 | | |
1388 | 123k | if (ch->rotate || ch->skew) |
1389 | 66.4k | { |
1390 | 66.4k | ch->kxsin = readS32(); |
1391 | 66.4k | ch->kysin = readS32(); |
1392 | 66.4k | ch->matrix.element[1][0] = (double)(ch->kxsin)/65536; |
1393 | 66.4k | ch->matrix.element[0][1] = (double)(ch->kysin)/65536; |
1394 | 66.4k | } |
1395 | | |
1396 | 123k | if (ch->translate) |
1397 | 62.6k | { |
1398 | 62.6k | ch->txfraction = readU16(); |
1399 | 62.6k | ch->txinteger = readS32(); |
1400 | 62.6k | ch->tyfraction = readU16(); |
1401 | 62.6k | ch->tyinteger = readS32(); |
1402 | 62.6k | ch->matrix.element[2][0] = (double)(ch->txinteger); |
1403 | 62.6k | ch->matrix.element[2][1] = (double)(ch->tyinteger); |
1404 | 62.6k | } |
1405 | | |
1406 | 123k | if (ch->taper) |
1407 | 75.3k | { |
1408 | 75.3k | ch->px = readS32(); |
1409 | 75.3k | ch->py = readS32(); |
1410 | 75.3k | ch->matrix.element[0][2] = (double)(ch->px); |
1411 | 75.3k | ch->matrix.element[1][2] = (double)(ch->py); |
1412 | 75.3k | } |
1413 | | |
1414 | 123k | WPG_DEBUG_MSG(("ObjectCharacterization\n")); |
1415 | 123k | WPG_DEBUG_MSG((" taper : %s\n", (ch->taper ? "yes" : "no"))); |
1416 | 123k | WPG_DEBUG_MSG((" translate : %s\n", (ch->translate ? "yes" : "no"))); |
1417 | 123k | WPG_DEBUG_MSG((" skew : %s\n", (ch->skew ? "yes" : "no"))); |
1418 | 123k | WPG_DEBUG_MSG((" scale : %s\n", (ch->scale ? "yes" : "no"))); |
1419 | 123k | WPG_DEBUG_MSG((" rotate : %s\n", (ch->rotate ? "yes" : "no"))); |
1420 | 123k | WPG_DEBUG_MSG((" hasObjectId : %s\n", (ch->hasObjectId ? "yes" : "no"))); |
1421 | 123k | WPG_DEBUG_MSG((" editLock : %s\n", (ch->editLock ? "yes" : "no"))); |
1422 | 123k | WPG_DEBUG_MSG((" closed : %s\n", (ch->closed ? "yes" : "no"))); |
1423 | 123k | WPG_DEBUG_MSG((" framed : %s\n", (ch->framed ? "yes" : "no"))); |
1424 | 123k | WPG_DEBUG_MSG((" filled : %s\n", (ch->filled ? "yes" : "no"))); |
1425 | | #ifdef DEBUG |
1426 | | if (ch->editLock) WPG_DEBUG_MSG((" lock flags : 0x%x\n", (unsigned)ch->lockFlags)); |
1427 | | if (ch->hasObjectId) WPG_DEBUG_MSG((" object ID : 0x%x\n", (unsigned)ch->objectId)); |
1428 | | if (ch->translate) WPG_DEBUG_MSG((" tx : %li %d\n", ch->txinteger, ch->txfraction)); |
1429 | | if (ch->translate) WPG_DEBUG_MSG((" ty : %li %d\n", ch->tyinteger, ch->tyfraction)); |
1430 | | #endif |
1431 | 123k | WPG_DEBUG_MSG(("transform matrix:\n")); |
1432 | 123k | WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[0][0], ch->matrix.element[0][1],ch->matrix.element[0][2])); |
1433 | 123k | WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[1][0], ch->matrix.element[1][1],ch->matrix.element[1][2])); |
1434 | 123k | WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[2][0], ch->matrix.element[2][1],ch->matrix.element[2][2])); |
1435 | 123k | } |
1436 | | |
1437 | | void WPG2Parser::handlePolyline() |
1438 | 11.4k | { |
1439 | 11.4k | if (!m_graphicsStarted) |
1440 | 469 | return; |
1441 | 11.0k | ObjectCharacterization objCh; |
1442 | 11.0k | parseCharacterization(&objCh); |
1443 | 11.0k | m_matrix = objCh.matrix; |
1444 | | |
1445 | 11.0k | librevenge::RVNGPropertyList tmpStyle = m_style; |
1446 | | |
1447 | 11.0k | if (!objCh.filled) |
1448 | 6.43k | tmpStyle.insert("draw:fill", "none"); |
1449 | 11.0k | if (!objCh.framed) |
1450 | 10.3k | tmpStyle.insert("draw:stroke", "none"); |
1451 | | |
1452 | 11.0k | bool insideCompound = m_groupStack.empty() ? false : |
1453 | 11.0k | m_groupStack.top().isCompoundPolygon(); |
1454 | | |
1455 | | // inside a compound, so take the parent transformation into account |
1456 | 11.0k | if (insideCompound) |
1457 | 5.25k | m_matrix.transformBy(m_groupStack.top().compoundMatrix); |
1458 | | |
1459 | 11.0k | unsigned long count = readU16(); |
1460 | 11.0k | const unsigned long maxCount = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 2; |
1461 | 11.0k | if (count > maxCount) |
1462 | 6.18k | count = maxCount; |
1463 | | |
1464 | 11.0k | librevenge::RVNGPropertyListVector points; |
1465 | 130k | for (unsigned long i = 0; i < count; i++) |
1466 | 119k | { |
1467 | 119k | librevenge::RVNGPropertyList point; |
1468 | 119k | long x = (m_doublePrecision) ? readS32() : readS16(); |
1469 | 119k | long y = (m_doublePrecision) ? readS32() : readS16(); |
1470 | 119k | transformXY(x,y); |
1471 | 119k | point.insert("svg:x", (toDouble(x)/m_xres)); |
1472 | 119k | point.insert("svg:y", (toDouble(y)/m_yres)); |
1473 | 119k | points.append(point); |
1474 | 119k | } |
1475 | | |
1476 | 11.0k | librevenge::RVNGPropertyList tmpPoints; |
1477 | 11.0k | tmpPoints.insert("svg:points", points); |
1478 | | |
1479 | 11.0k | if (insideCompound) |
1480 | 5.25k | { |
1481 | 5.25k | if (count > 0) |
1482 | 364 | { |
1483 | | // inside a compound ? convert it into path because for compound |
1484 | | // we will only use paths |
1485 | 364 | librevenge::RVNGPropertyListVector &path = m_groupStack.top().compoundPath; |
1486 | 364 | librevenge::RVNGPropertyList element; |
1487 | 364 | element = points[0]; |
1488 | 364 | element.insert("librevenge:path-action", "M"); |
1489 | 364 | path.append(element); |
1490 | 100k | for (unsigned long ii = 1; ii < count; ii++) |
1491 | 100k | { |
1492 | 100k | element.clear(); |
1493 | 100k | element = points[ii]; |
1494 | 100k | element.insert("librevenge:path-action", "L"); |
1495 | 100k | path.append(element); |
1496 | 100k | } |
1497 | 364 | } |
1498 | 5.25k | } |
1499 | 5.76k | else |
1500 | 5.76k | { |
1501 | | // otherwise draw directly |
1502 | 5.76k | if (count > 2) |
1503 | 507 | { |
1504 | 507 | if (objCh.windingRule) |
1505 | 89 | tmpStyle.insert("svg:fill-rule", "nonzero"); |
1506 | 418 | else |
1507 | 418 | tmpStyle.insert("svg:fill-rule", "evenodd"); |
1508 | | |
1509 | 507 | if (objCh.filled || m_gradient.count()) |
1510 | 163 | tmpStyle.insert("svg:linearGradient", m_gradient); |
1511 | 507 | m_painter->setStyle(tmpStyle); |
1512 | | |
1513 | 507 | if (objCh.filled || objCh.closed) |
1514 | 160 | m_painter->drawPolygon(tmpPoints); |
1515 | 347 | else |
1516 | 347 | m_painter->drawPolyline(tmpPoints); |
1517 | 507 | } |
1518 | 5.26k | else |
1519 | 5.26k | { |
1520 | | |
1521 | 5.26k | m_painter->setStyle(tmpStyle); |
1522 | 5.26k | m_painter->drawPolyline(tmpPoints); |
1523 | 5.26k | } |
1524 | 5.76k | } |
1525 | | |
1526 | 11.0k | WPG_DEBUG_MSG((" Vertices count : %li\n", (long) count)); |
1527 | 130k | for (unsigned long j = 0; j < count; j++) |
1528 | 119k | WPG_DEBUG_MSG((" Point #%lu : %g,%g\n", j+1, points[j]["svg:x"]->getDouble(), points[j]["svg:x"]->getDouble())); |
1529 | 11.0k | } |
1530 | | |
1531 | | void WPG2Parser::handlePolyspline() |
1532 | 6.71k | { |
1533 | | // fprintf(stderr, "This is actually not an error, just a crash so that we know "); |
1534 | | // fprintf(stderr, "that there is an actual document containing the Polyspline record\n"); |
1535 | | // crash here !!! |
1536 | | // *((int *)NULL) = 0; |
1537 | 6.71k | if (!m_graphicsStarted) |
1538 | 222 | return; |
1539 | | // We have never seen a polyspline in a WPG file and we are not even able to generate |
1540 | | // one, so, we draw a polyline instead and wait for bug reports :) |
1541 | 6.49k | handlePolyline(); |
1542 | 6.49k | } |
1543 | | |
1544 | | void WPG2Parser::handlePolycurve() |
1545 | 47.0k | { |
1546 | 47.0k | if (!m_graphicsStarted) |
1547 | 288 | return; |
1548 | 46.7k | ObjectCharacterization objCh; |
1549 | 46.7k | parseCharacterization(&objCh); |
1550 | 46.7k | m_matrix = objCh.matrix; |
1551 | | |
1552 | 46.7k | librevenge::RVNGPropertyList tmpStyle = m_style; |
1553 | | |
1554 | 46.7k | if (!objCh.filled) |
1555 | 45.1k | tmpStyle.insert("draw:fill", "none"); |
1556 | 46.7k | if (!objCh.framed) |
1557 | 45.8k | tmpStyle.insert("draw:stroke", "none"); |
1558 | | |
1559 | 46.7k | bool insideCompound = m_groupStack.empty() ? false : |
1560 | 46.7k | m_groupStack.top().isCompoundPolygon(); |
1561 | | |
1562 | | // inside a compound, so take the parent transformation into account |
1563 | 46.7k | if (insideCompound) |
1564 | 3.48k | m_matrix.transformBy(m_groupStack.top().compoundMatrix); |
1565 | | |
1566 | 46.7k | unsigned int count = readU16(); |
1567 | 46.7k | const unsigned int maxCount = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 6; |
1568 | 46.7k | if (count > maxCount) |
1569 | 43.5k | count = maxCount; |
1570 | | |
1571 | 46.7k | librevenge::RVNGPropertyListVector path; |
1572 | 46.7k | librevenge::RVNGPropertyList element; |
1573 | 46.7k | librevenge::RVNGPropertyListVector vertices; |
1574 | 46.7k | librevenge::RVNGPropertyListVector controlPoints; |
1575 | 411k | for (unsigned int i = 0; i < count; i++) |
1576 | 365k | { |
1577 | 365k | long ix = (m_doublePrecision) ? readS32() : readS16(); |
1578 | 365k | long iy = (m_doublePrecision) ? readS32() : readS16(); |
1579 | 365k | transformXY(ix,iy); |
1580 | | |
1581 | 365k | long ax = (m_doublePrecision) ? readS32() : readS16(); |
1582 | 365k | long ay = (m_doublePrecision) ? readS32() : readS16(); |
1583 | 365k | transformXY(ax,ay); |
1584 | | |
1585 | 365k | long tx = (m_doublePrecision) ? readS32() : readS16(); |
1586 | 365k | long ty = (m_doublePrecision) ? readS32() : readS16(); |
1587 | 365k | transformXY(tx,ty); |
1588 | | |
1589 | 365k | element.insert("svg:x", (toDouble(ax)/m_xres)); |
1590 | 365k | element.insert("svg:y", (toDouble(ay)/m_yres)); |
1591 | 365k | if (i == 0) |
1592 | 458 | element.insert("librevenge:path-action", "M"); |
1593 | 364k | else |
1594 | 364k | { |
1595 | 364k | element.insert("svg:x2", (toDouble(ix)/m_xres)); |
1596 | 364k | element.insert("svg:y2", (toDouble(iy)/m_yres)); |
1597 | 364k | element.insert("librevenge:path-action", "C"); |
1598 | 364k | } |
1599 | 365k | path.append(element); |
1600 | 365k | element.insert("svg:x1", (toDouble(tx)/m_xres)); |
1601 | 365k | element.insert("svg:y1", (toDouble(ty)/m_yres)); |
1602 | 365k | } |
1603 | | |
1604 | 46.7k | element.clear(); |
1605 | 46.7k | if (objCh.closed) |
1606 | 1.05k | { |
1607 | 1.05k | element.insert("librevenge:path-action", "Z"); |
1608 | 1.05k | path.append(element); |
1609 | 1.05k | } |
1610 | | |
1611 | 46.7k | if (insideCompound) |
1612 | | // inside a compound ? just collect the path together |
1613 | 3.48k | m_groupStack.top().compoundPath.append(path); |
1614 | 43.2k | else |
1615 | 43.2k | { |
1616 | | // otherwise draw directly |
1617 | 43.2k | if (objCh.windingRule) |
1618 | 42.0k | tmpStyle.insert("svg:fill-rule", "nonzero"); |
1619 | 1.16k | else |
1620 | 1.16k | tmpStyle.insert("svg:fill-rule", "evenodd"); |
1621 | 43.2k | if (objCh.filled || m_gradient.count()) |
1622 | 1.68k | tmpStyle.insert("svg:linearGradient", m_gradient); |
1623 | 43.2k | m_painter->setStyle(tmpStyle); |
1624 | 43.2k | librevenge::RVNGPropertyList propList; |
1625 | 43.2k | propList.insert("svg:d", path); |
1626 | 43.2k | m_painter->drawPath(propList); |
1627 | 43.2k | } |
1628 | 46.7k | } |
1629 | | |
1630 | | void WPG2Parser::handleRectangle() |
1631 | 7.28k | { |
1632 | 7.28k | if (!m_graphicsStarted) |
1633 | 195 | return; |
1634 | 7.09k | ObjectCharacterization objCh; |
1635 | 7.09k | parseCharacterization(&objCh); |
1636 | 7.09k | m_matrix = objCh.matrix; |
1637 | | |
1638 | 7.09k | librevenge::RVNGPropertyList tmpStyle = m_style; |
1639 | | |
1640 | 7.09k | if (!objCh.filled) |
1641 | 6.82k | tmpStyle.insert("draw:fill", "none"); |
1642 | 7.09k | if (!objCh.framed) |
1643 | 6.80k | tmpStyle.insert("draw:stroke", "none"); |
1644 | | |
1645 | 7.09k | long x1 = (m_doublePrecision) ? readS32() : readS16(); |
1646 | 7.09k | long y1 = (m_doublePrecision) ? readS32() : readS16(); |
1647 | 7.09k | transformXY(x1,y1); |
1648 | | |
1649 | 7.09k | long x2 = (m_doublePrecision) ? readS32() : readS16(); |
1650 | 7.09k | long y2 = (m_doublePrecision) ? readS32() : readS16(); |
1651 | 7.09k | transformXY(x2,y2); |
1652 | | |
1653 | 7.09k | long xs1 = (x1 <= x2) ? x1 : x2; |
1654 | 7.09k | long xs2 = (x1 <= x2) ? x2 : x1; |
1655 | 7.09k | long ys1 = (y1 <= y2) ? y1 : y2; |
1656 | 7.09k | long ys2 = (y1 <= y2) ? y2 : y1; |
1657 | | |
1658 | 7.09k | long rx = (m_doublePrecision) ? readS32() : readS16(); |
1659 | 7.09k | long ry = (m_doublePrecision) ? readS32() : readS16(); |
1660 | | |
1661 | 7.09k | librevenge::RVNGPropertyList propList; |
1662 | 7.09k | propList.insert("svg:x", (toDouble(xs1) / m_xres)); |
1663 | 7.09k | propList.insert("svg:width", (toDouble(xs2-xs1) / m_xres)); |
1664 | 7.09k | propList.insert("svg:y", (toDouble(ys1) / m_yres)); |
1665 | 7.09k | propList.insert("svg:height", (toDouble(ys2-ys1) / m_yres)); |
1666 | | |
1667 | 7.09k | propList.insert("svg:rx", (toDouble(rx)/m_xres)); |
1668 | 7.09k | propList.insert("svg:ry", (toDouble(ry)/m_yres)); |
1669 | | |
1670 | 7.09k | if (objCh.filled || m_gradient.count()) |
1671 | 599 | tmpStyle.insert("svg:linearGradient", m_gradient); |
1672 | 7.09k | m_painter->setStyle(tmpStyle); |
1673 | 7.09k | m_painter->drawRectangle(propList); |
1674 | | |
1675 | 7.09k | WPG_DEBUG_MSG((" X1 : %li\n", x1)); |
1676 | 7.09k | WPG_DEBUG_MSG((" Y1 : %li\n", y1)); |
1677 | 7.09k | WPG_DEBUG_MSG((" X2 : %li\n", x2)); |
1678 | 7.09k | WPG_DEBUG_MSG((" Y2 : %li\n", y2)); |
1679 | 7.09k | WPG_DEBUG_MSG((" Round X : %li\n", rx)); |
1680 | 7.09k | WPG_DEBUG_MSG((" Round Y : %li\n", ry)); |
1681 | 7.09k | } |
1682 | | |
1683 | | void WPG2Parser::handleArc() |
1684 | 5.72k | { |
1685 | 5.72k | if (!m_graphicsStarted) |
1686 | 443 | return; |
1687 | 5.28k | ObjectCharacterization objCh; |
1688 | 5.28k | parseCharacterization(&objCh); |
1689 | 5.28k | m_matrix = objCh.matrix; |
1690 | | |
1691 | 5.28k | librevenge::RVNGPropertyList tmpStyle = m_style; |
1692 | | |
1693 | 5.28k | if (!objCh.filled) |
1694 | 4.40k | tmpStyle.insert("draw:fill", "none"); |
1695 | 5.28k | if (!objCh.framed) |
1696 | 5.17k | tmpStyle.insert("draw:stroke", "none"); |
1697 | | |
1698 | 5.28k | long cx = (m_doublePrecision) ? readS32() : readS16(); |
1699 | 5.28k | long cy = (m_doublePrecision) ? readS32() : readS16(); |
1700 | | |
1701 | 5.28k | long radx = (m_doublePrecision) ? readS32() : readS16(); |
1702 | 5.28k | long rady = (m_doublePrecision) ? readS32() : readS16(); |
1703 | | |
1704 | 5.28k | long ix = (m_doublePrecision) ? readS32() : readS16(); |
1705 | 5.28k | ix += cx; |
1706 | 5.28k | long iy = (m_doublePrecision) ? readS32() : readS16(); |
1707 | 5.28k | iy += cy; |
1708 | | |
1709 | 5.28k | long ex = (m_doublePrecision) ? readS32() : readS16(); |
1710 | 5.28k | ex += cx; |
1711 | 5.28k | long ey = (m_doublePrecision) ? readS32() : readS16(); |
1712 | 5.28k | ey += cy; |
1713 | | |
1714 | 5.28k | transformXY(cx,cy); |
1715 | 5.28k | transformXY(ix,iy); |
1716 | 5.28k | transformXY(ex,ey); |
1717 | | |
1718 | 5.28k | if (objCh.filled || m_gradient.count()) |
1719 | 1.23k | tmpStyle.insert("svg:linearGradient", m_gradient); |
1720 | 5.28k | m_painter->setStyle(tmpStyle); |
1721 | | |
1722 | 5.28k | if (ix == ex && iy == ey) |
1723 | 1.45k | { |
1724 | 1.45k | librevenge::RVNGPropertyList propList; |
1725 | 1.45k | propList.insert("svg:cx", (toDouble(cx) / m_xres)); |
1726 | 1.45k | propList.insert("svg:cy", (toDouble(cy) / m_xres)); |
1727 | 1.45k | propList.insert("svg:rx", (toDouble(radx) / m_xres)); |
1728 | 1.45k | propList.insert("svg:ry", (toDouble(rady) / m_xres)); |
1729 | 1.45k | if (objCh.rotate) |
1730 | 904 | propList.insert("librevenge:rotate", objCh.rotationAngle, librevenge::RVNG_GENERIC); |
1731 | | |
1732 | 1.45k | m_painter->drawEllipse(propList); |
1733 | 1.45k | } |
1734 | 3.82k | else |
1735 | 3.82k | { |
1736 | 3.82k | librevenge::RVNGPropertyList element; |
1737 | 3.82k | librevenge::RVNGPropertyListVector path; |
1738 | | |
1739 | 3.82k | element.insert("librevenge:path-action", "M"); |
1740 | 3.82k | element.insert("svg:x", (toDouble(ix)/m_xres)); |
1741 | 3.82k | element.insert("svg:y", (toDouble(iy)/m_yres)); |
1742 | 3.82k | path.append(element); |
1743 | 3.82k | element.clear(); |
1744 | | |
1745 | 3.82k | element.insert("librevenge:path-action", "A"); |
1746 | 3.82k | element.insert("svg:rx", (toDouble(radx)/m_xres)); |
1747 | 3.82k | element.insert("svg:ry", (toDouble(rady)/m_yres)); |
1748 | 3.82k | element.insert("svg:x", (toDouble(ex)/m_xres)); |
1749 | 3.82k | element.insert("svg:y", (toDouble(ey)/m_yres)); |
1750 | 3.82k | if (objCh.rotate) |
1751 | 1.45k | element.insert("librevenge:rotate", objCh.rotationAngle, librevenge::RVNG_GENERIC); |
1752 | 3.82k | path.append(element); |
1753 | | |
1754 | 3.82k | librevenge::RVNGPropertyList propList; |
1755 | 3.82k | propList.insert("svg:d", path); |
1756 | 3.82k | m_painter->drawPath(propList); |
1757 | 3.82k | } |
1758 | | |
1759 | 5.28k | WPG_DEBUG_MSG((" Center point x : %li\n", cx)); |
1760 | 5.28k | WPG_DEBUG_MSG((" Center point y : %li\n", cy)); |
1761 | 5.28k | WPG_DEBUG_MSG((" Radius x : %li\n", radx)); |
1762 | 5.28k | WPG_DEBUG_MSG((" Radius y : %li\n", rady)); |
1763 | 5.28k | WPG_DEBUG_MSG((" Initial point x : %li\n", ix)); |
1764 | 5.28k | WPG_DEBUG_MSG((" Initial point y : %li\n", iy)); |
1765 | 5.28k | WPG_DEBUG_MSG((" End point x : %li\n", ex)); |
1766 | 5.28k | WPG_DEBUG_MSG((" End point y : %li\n", ey)); |
1767 | 5.28k | } |
1768 | | |
1769 | | void WPG2Parser::handleBitmap() |
1770 | 4.84k | { |
1771 | 4.84k | if (!m_graphicsStarted) |
1772 | 197 | return; |
1773 | 4.64k | ObjectCharacterization objCh; |
1774 | 4.64k | parseCharacterization(&objCh); |
1775 | | |
1776 | 4.64k | if (objCh.scale) |
1777 | 2.96k | { |
1778 | 2.96k | if (objCh.sxcos < 0) |
1779 | 822 | m_hFlipped = true; |
1780 | 2.96k | if (objCh.sycos < 0) |
1781 | 616 | m_vFlipped = true; |
1782 | 2.96k | } |
1783 | 4.64k | m_matrix = objCh.matrix; |
1784 | | |
1785 | 4.64k | long x1 = (m_doublePrecision) ? readS32() : readS16(); |
1786 | 4.64k | long y1 = (m_doublePrecision) ? readS32() : readS16(); |
1787 | 4.64k | long x2 = (m_doublePrecision) ? readS32() : readS16(); |
1788 | 4.64k | long y2 = (m_doublePrecision) ? readS32() : readS16(); |
1789 | 4.64k | transformXY(x1,y1); |
1790 | 4.64k | transformXY(x2,y2); |
1791 | | |
1792 | 4.64k | long hres = (m_doublePrecision) ? readS32() : readS16(); |
1793 | 4.64k | long vres = (m_doublePrecision) ? readS32() : readS16(); |
1794 | | |
1795 | 4.64k | long xs1 = (x1 <= x2) ? x1 : x2; |
1796 | 4.64k | long xs2 = (x1 <= x2) ? x2 : x1; |
1797 | 4.64k | long ys1 = (y1 <= y2) ? y1 : y2; |
1798 | 4.64k | long ys2 = (y1 <= y2) ? y2 : y1; |
1799 | | |
1800 | 4.64k | m_bitmap.x1 = toDouble(xs1) / m_xres; |
1801 | 4.64k | m_bitmap.y1 = toDouble(ys1) / m_yres; |
1802 | 4.64k | m_bitmap.x2 = toDouble(xs2) / m_xres; |
1803 | 4.64k | m_bitmap.y2 = toDouble(ys2) / m_yres; |
1804 | 4.64k | if (hres == 0) |
1805 | 1.19k | hres = 72; |
1806 | 4.64k | m_bitmap.hres = hres; |
1807 | 4.64k | if (vres == 0) |
1808 | 1.32k | vres = 72; |
1809 | 4.64k | m_bitmap.vres = vres; |
1810 | | |
1811 | 4.64k | WPG_DEBUG_MSG((" x1 : %li\n", x1)); |
1812 | 4.64k | WPG_DEBUG_MSG((" y1 : %li\n", y1)); |
1813 | 4.64k | WPG_DEBUG_MSG((" x2 : %li\n", x2)); |
1814 | 4.64k | WPG_DEBUG_MSG((" y2 : %li\n", y2)); |
1815 | 4.64k | WPG_DEBUG_MSG((" hres : %li (pixel per inch)\n", hres)); |
1816 | 4.64k | WPG_DEBUG_MSG((" vres : %li (pixel per inch)\n", vres)); |
1817 | 4.64k | } |
1818 | | |
1819 | | void WPG2Parser::handleBitmapData() |
1820 | 11.9k | { |
1821 | 11.9k | if (!m_graphicsStarted) |
1822 | 233 | return; |
1823 | 11.7k | unsigned width = readU16(); |
1824 | 11.7k | unsigned height = readU16(); |
1825 | 11.7k | unsigned color_format = readU8(); |
1826 | 11.7k | unsigned compression_format = readU8(); |
1827 | | |
1828 | 11.7k | WPG_DEBUG_MSG((" dimension : %g, %g %g, %g\n", m_bitmap.x1, m_bitmap.y1, m_bitmap.x2, m_bitmap.y2)); |
1829 | 11.7k | WPG_DEBUG_MSG((" width : %i pixels\n", (int) width)); |
1830 | 11.7k | WPG_DEBUG_MSG((" height : %i pixels\n", (int) height)); |
1831 | 11.7k | WPG_DEBUG_MSG((" color format : %d\n", (int) color_format)); |
1832 | 11.7k | WPG_DEBUG_MSG((" compression : %d (%s)\n", (int) compression_format, |
1833 | 11.7k | (compression_format==0) ? "uncompressed": |
1834 | 11.7k | (compression_format==1) ? "run-length encoding" : "unknown")); |
1835 | | |
1836 | 11.7k | if (color_format > 12) // not documented and we are likely not knowing what to do with this |
1837 | 568 | return; |
1838 | 11.1k | unsigned tmpBufferSize; |
1839 | 11.1k | unsigned raster_len = width; |
1840 | 11.1k | if (color_format == 1) |
1841 | 842 | { |
1842 | 842 | tmpBufferSize = (width/8+1)*height; |
1843 | 842 | raster_len = width/8 + ((width % 8) ? 1 : 0); |
1844 | 842 | } |
1845 | 10.2k | else if (color_format == 2) |
1846 | 1.25k | { |
1847 | 1.25k | tmpBufferSize = (width/4+1)*height; |
1848 | 1.25k | raster_len = width/4 + ((width % 4) ? 1 : 0); |
1849 | 1.25k | } |
1850 | 9.03k | else if (color_format == 3) |
1851 | 488 | { |
1852 | 488 | tmpBufferSize = (width/2+1)*height; |
1853 | 488 | raster_len = width/2 + ((width % 2) ? 1 : 0); |
1854 | 488 | } |
1855 | 8.55k | else if (color_format == 5 || color_format == 6 || color_format == 7) |
1856 | 2.04k | tmpBufferSize = 2*width*height; |
1857 | 6.50k | else if (color_format == 8) |
1858 | 1.64k | tmpBufferSize = 3*width*height; |
1859 | 4.86k | else if (color_format == 9) |
1860 | 166 | tmpBufferSize = 4*width*height; |
1861 | 4.69k | else if (color_format == 10) |
1862 | 566 | tmpBufferSize = 6*width*height; |
1863 | 4.12k | else if (color_format == 11) |
1864 | 103 | tmpBufferSize = 8*width*height; |
1865 | 4.02k | else |
1866 | 4.02k | tmpBufferSize = width*height; |
1867 | | |
1868 | | |
1869 | 11.1k | std::vector<unsigned char> buffer; |
1870 | | |
1871 | | // plain data, uncompression |
1872 | 11.1k | if (compression_format==0) |
1873 | 3.34k | { |
1874 | 3.34k | if (tmpBufferSize > getRemainingLength(m_input)) |
1875 | 1.02k | return; |
1876 | 2.32k | buffer.reserve(tmpBufferSize); |
1877 | 173k | for (unsigned ii=0; ii < tmpBufferSize && !m_input->isEnd() && m_input->tell() <= m_recordEnd; ii++) |
1878 | 170k | buffer.push_back(readU8()); |
1879 | 2.32k | } |
1880 | | // run-length encoding |
1881 | 7.78k | else if (compression_format==1) |
1882 | 6.45k | { |
1883 | 6.45k | unsigned char data[256]; |
1884 | 6.45k | bool xor_raster = false; |
1885 | 6.45k | unsigned next_scanline = 0; |
1886 | 6.45k | unsigned data_size = 1; |
1887 | 6.45k | data[0] = 0; |
1888 | | |
1889 | 6.45k | if (!checkRLESize(tmpBufferSize)) |
1890 | 1.50k | return; |
1891 | | |
1892 | 4.94k | WPG_DEBUG_MSG(("Decoding RLE data\n")); |
1893 | | |
1894 | | // FIXME check for ptr, it should not go out of bound!! |
1895 | 273k | while (m_input->tell() <= m_recordEnd && !m_input->isEnd() && buffer.size() < tmpBufferSize) |
1896 | 268k | { |
1897 | 268k | unsigned char opcode = readU8(); |
1898 | | // specify data size |
1899 | 268k | if (opcode == 0x7d) |
1900 | 2.48k | { |
1901 | 2.48k | unsigned new_data_size = readU8(); |
1902 | 2.48k | if (new_data_size != data_size) |
1903 | 1.48k | { |
1904 | 1.48k | data_size = new_data_size; |
1905 | 1.48k | std::memset(data, 0, data_size); |
1906 | 1.48k | if (tmpBufferSize < data_size*width*height) |
1907 | 788 | { |
1908 | 788 | tmpBufferSize = data_size*width*height; |
1909 | 788 | if (!checkRLESize(tmpBufferSize)) |
1910 | 150 | return; |
1911 | 638 | buffer.reserve(tmpBufferSize); |
1912 | 638 | } |
1913 | 1.33k | raster_len = data_size*width; |
1914 | 1.33k | } |
1915 | 2.48k | } |
1916 | | |
1917 | | // a run of black (index #0) |
1918 | 266k | else if (opcode == 0x7f) |
1919 | 1.54k | { |
1920 | 1.54k | unsigned count = 1 + readU8(); |
1921 | 194k | for (; count ; --count) |
1922 | 24.3M | for (unsigned j = 0; j < data_size; j++) |
1923 | 24.1M | buffer.push_back(0); |
1924 | | |
1925 | 1.54k | } |
1926 | | |
1927 | | // a run of white (index #255) |
1928 | 264k | else if (opcode == 0xff) |
1929 | 29.8k | { |
1930 | 29.8k | unsigned count = 1 + readU8(); |
1931 | | |
1932 | 7.24M | for (; count ; --count) |
1933 | 196M | for (unsigned j = 0; j < data_size; j++) |
1934 | 189M | buffer.push_back(255); |
1935 | 29.8k | } |
1936 | | |
1937 | | // extend previous run |
1938 | 235k | else if (opcode == 0xfd) |
1939 | 2.39k | { |
1940 | 2.39k | unsigned count = 1 + readU8(); |
1941 | 536k | for (; count; --count) |
1942 | 52.1M | for (unsigned j = 0; j < data_size; j++) |
1943 | 51.6M | buffer.push_back(data[j]); |
1944 | 2.39k | } |
1945 | | |
1946 | | // repeat raster |
1947 | 232k | else if (opcode == 0xfe) |
1948 | 1.75k | { |
1949 | 1.75k | unsigned count = 1 + readU8(); |
1950 | 1.75k | if (buffer.size() < raster_len) |
1951 | 23 | break; |
1952 | 1.73k | unsigned raster_source = buffer.size() - raster_len; |
1953 | 321k | for (; count; --count) |
1954 | 148M | for (unsigned long r = 0; r < raster_len; r++) |
1955 | 147M | { |
1956 | 147M | unsigned char pixel = buffer[raster_source + r]; |
1957 | 147M | buffer.push_back(pixel); |
1958 | 147M | } |
1959 | 1.73k | } |
1960 | | |
1961 | | // XOR |
1962 | 230k | else if (opcode == 0x7e) |
1963 | 3.87k | { |
1964 | | // Xor-ing will happen when about to enter next raster |
1965 | | // see after the last if down below |
1966 | 3.87k | xor_raster = true; |
1967 | 3.87k | next_scanline = buffer.size() + raster_len; |
1968 | 3.87k | } |
1969 | | |
1970 | | // NOTE: the following two IFs here must be the last ones |
1971 | | |
1972 | | // a run of data |
1973 | 226k | else if (opcode >= 0x80) |
1974 | 23.5k | { |
1975 | 23.5k | unsigned count = 1 + (opcode & 0x7f); |
1976 | 23.5k | unsigned i = 0; |
1977 | 245k | for (; i < data_size && !m_input->isEnd(); i++) |
1978 | 221k | data[i] = readU8(); |
1979 | 30.1k | while (i < data_size) |
1980 | 6.54k | data[i++] = 0; |
1981 | 1.88M | for (; count; --count) |
1982 | 18.6M | for (unsigned j = 0; j < data_size; j++) |
1983 | 16.7M | buffer.push_back(data[j]); |
1984 | 23.5k | } |
1985 | | |
1986 | | // simple copy |
1987 | 203k | else if (opcode <= 0x7f) |
1988 | 203k | { |
1989 | 203k | unsigned count = opcode + 1; |
1990 | 1.43M | for (; count; --count) |
1991 | 4.41M | for (unsigned j = 0; j < data_size && !m_input->isEnd(); j++) |
1992 | 3.18M | buffer.push_back(readU8()); |
1993 | 203k | } |
1994 | | |
1995 | | // unreachable: only sentinel |
1996 | 0 | else |
1997 | 0 | { |
1998 | 0 | WPG_DEBUG_MSG((" ! unknown opcode %02x\n", opcode)); |
1999 | 0 | break; |
2000 | 0 | } |
2001 | | |
2002 | | // new raster/scanline? if necessary do the XOR now |
2003 | 268k | if (xor_raster && buffer.size() >= next_scanline) |
2004 | 1.30k | { |
2005 | | // reset, because XOR in one raster at a time |
2006 | 1.30k | xor_raster = false; |
2007 | | |
2008 | 1.30k | if (raster_len > next_scanline / 2) |
2009 | 77 | return; |
2010 | | |
2011 | | // current raster must be XORed with previous raster |
2012 | 1.22k | unsigned current = next_scanline - raster_len; |
2013 | 1.22k | unsigned previous = current - raster_len; |
2014 | 145k | for (unsigned r = 0; r < raster_len; r++) |
2015 | 144k | buffer[current++] ^= buffer[previous++]; |
2016 | | |
2017 | 1.22k | } |
2018 | | |
2019 | 268k | } |
2020 | | |
2021 | 4.72k | WPG_DEBUG_MSG(("Finish decoding RLE data\n")); |
2022 | 4.72k | } |
2023 | | |
2024 | | // no buffer? format is unknown |
2025 | 8.37k | if (!buffer.size()) return; |
2026 | | |
2027 | 112M | while (buffer.size() < tmpBufferSize) |
2028 | 112M | buffer.push_back(0); |
2029 | | |
2030 | | // prepare the bitmap structure for the listener |
2031 | 6.35k | libwpg::WPGBitmap bitmap((int) width, (int) height, m_vFlipped, m_hFlipped); |
2032 | 6.35k | librevenge::RVNGPropertyList propList; |
2033 | 6.35k | propList.insert("svg:x", (double)m_bitmap.x1); |
2034 | 6.35k | propList.insert("svg:y", (double)m_bitmap.y1); |
2035 | 6.35k | propList.insert("svg:width", (m_bitmap.x2 - m_bitmap.x1)); |
2036 | 6.35k | propList.insert("svg:height", (m_bitmap.y2 - m_bitmap.y1)); |
2037 | 6.35k | propList.insert("librevenge:mime-type", "image/bmp"); |
2038 | | |
2039 | | // format 1: each byte represents 8 pixels, the color fetched from the palette |
2040 | 6.35k | if (color_format == 1) |
2041 | 579 | { |
2042 | 579 | size_t i = 0; |
2043 | 809k | for (unsigned long y = 0; y < height; y++) |
2044 | 4.91M | for (unsigned long x = 0; x < width; x++, i++) |
2045 | 4.10M | { |
2046 | 4.10M | if ((x==0) && (i % 8 != 0)) |
2047 | 429k | i = (i/8 + 1) * 8; |
2048 | 4.10M | unsigned index = ((buffer[i/8] & (0x01 << (7 - (i % 8)))) >> (7 - (i % 8))); |
2049 | 4.10M | const libwpg::WPGColor &color = m_colorPalette[(int) index]; |
2050 | 4.10M | bitmap.setPixel((int) x, (int) y, color); |
2051 | 4.10M | } |
2052 | 579 | propList.insert("office:binary-data", bitmap.getDIB()); |
2053 | 579 | m_painter->drawGraphicObject(propList); |
2054 | 579 | } |
2055 | | // format 2: each byte represents 4 pixels, the color fetched from the palette |
2056 | 5.77k | else if (color_format == 2) |
2057 | 831 | { |
2058 | 831 | size_t i = 0; |
2059 | 1.76M | for (unsigned long y = 0; y < height; y++) |
2060 | 7.66M | for (unsigned long x = 0; x < width; x++, i++) |
2061 | 5.90M | { |
2062 | 5.90M | if ((x==0) && (i % 4 != 0)) |
2063 | 1.65M | i = (i/4 + 1) * 4; |
2064 | 5.90M | unsigned index = ((buffer[i/4] & (0x03 << 2*(3 - (i % 4)))) >> 2*(3 - (i % 4))); |
2065 | 5.90M | const libwpg::WPGColor &color = m_colorPalette[(int) index]; |
2066 | 5.90M | bitmap.setPixel((int) x, (int) y, color); |
2067 | 5.90M | } |
2068 | 831 | propList.insert("office:binary-data", bitmap.getDIB()); |
2069 | 831 | m_painter->drawGraphicObject(propList); |
2070 | 831 | } |
2071 | | // format 3: each byte represents 2 pixels, the color fetched from the palette |
2072 | 4.94k | else if (color_format == 3) |
2073 | 128 | { |
2074 | 128 | int i = 0; |
2075 | 55.4k | for (unsigned long y = 0; y < height; y++) |
2076 | 281k | for (unsigned long x = 0; x < width; x++, i++) |
2077 | 225k | { |
2078 | 225k | if ((x==0) && (i % 2 != 0)) |
2079 | 6.16k | i = (i/2 + 1) * 2; |
2080 | 225k | unsigned index = ((buffer[size_t(i/2)] & (0x0f << 4*(1 - (i % 2)))) >> 4*(1 - (i % 2))); |
2081 | 225k | const libwpg::WPGColor &color = m_colorPalette[(int) index]; |
2082 | 225k | bitmap.setPixel((int) x, (int) y, color); |
2083 | 225k | } |
2084 | 128 | propList.insert("office:binary-data", bitmap.getDIB()); |
2085 | 128 | m_painter->drawGraphicObject(propList); |
2086 | 128 | } |
2087 | | // format 4: each byte represents a pixel, the color fetched from the palette |
2088 | 4.81k | else if (color_format == 4) |
2089 | 1.30k | { |
2090 | 1.30k | size_t i = 0; |
2091 | 392k | for (unsigned long y = 0; y < height; y++) |
2092 | 1.83M | for (unsigned long x = 0; x < width; x++, i++) |
2093 | 1.44M | { |
2094 | 1.44M | const libwpg::WPGColor &color = m_colorPalette[buffer[i]]; |
2095 | 1.44M | bitmap.setPixel((int) x, (int) y, color); |
2096 | 1.44M | } |
2097 | | |
2098 | 1.30k | propList.insert("office:binary-data", bitmap.getDIB()); |
2099 | 1.30k | m_painter->drawGraphicObject(propList); |
2100 | 1.30k | } |
2101 | | // format 5: greyscale of 16 bits |
2102 | 3.51k | else if (color_format == 5) |
2103 | 95 | { |
2104 | 95 | size_t i = 0; |
2105 | 2.41k | for (unsigned long y = 0; y < height; y++) |
2106 | 9.02k | for (unsigned long x = 0; x < width; x++, i++) |
2107 | 6.70k | { |
2108 | | |
2109 | 6.70k | const libwpg::WPGColor color(buffer[2*i+1], buffer[2*i+1], buffer[2*i+1]); |
2110 | 6.70k | bitmap.setPixel((int) x, (int) y, color); |
2111 | 6.70k | } |
2112 | | |
2113 | 95 | propList.insert("office:binary-data", bitmap.getDIB()); |
2114 | 95 | m_painter->drawGraphicObject(propList); |
2115 | 95 | } |
2116 | | // format 6: RGB, with 5 bits per colour |
2117 | 3.41k | else if (color_format == 6) |
2118 | 1.39k | { |
2119 | 1.39k | size_t i = 0; |
2120 | 386k | for (unsigned long y = 0; y < height; y++) |
2121 | 774k | for (unsigned long x = 0; x < width; x++, i++) |
2122 | 389k | { |
2123 | 389k | auto tmpColor = (unsigned short)(buffer[2*i] | (buffer[2*i+1] << 8)); |
2124 | 389k | const libwpg::WPGColor color((tmpColor >> 10) & 0x1f, (tmpColor >> 5) & 0x1f, tmpColor & 0x1f); |
2125 | 389k | bitmap.setPixel((int) x, (int) y, color); |
2126 | 389k | } |
2127 | | |
2128 | 1.39k | propList.insert("office:binary-data", bitmap.getDIB()); |
2129 | 1.39k | m_painter->drawGraphicObject(propList); |
2130 | 1.39k | } |
2131 | | // format 7: |
2132 | 2.02k | else if (color_format == 7) |
2133 | 181 | { |
2134 | 181 | size_t i = 0; |
2135 | 2.64k | for (unsigned long y = 0; y < height; y++) |
2136 | 198k | for (unsigned long x = 0; x < width; x++, i++) |
2137 | 196k | { |
2138 | 196k | auto tmpColor = (unsigned short)(buffer[2*i] | (buffer[2*i+1] << 8)); |
2139 | 196k | const libwpg::WPGColor color(tmpColor & 0x0f, (tmpColor >> 4) & 0x0f, (tmpColor >> 8) & 0x0f, (tmpColor >> 12) & 0x0f); |
2140 | 196k | bitmap.setPixel((int) x, (int) y, color); |
2141 | 196k | } |
2142 | | |
2143 | 181 | propList.insert("office:binary-data", bitmap.getDIB()); |
2144 | 181 | m_painter->drawGraphicObject(propList); |
2145 | 181 | } |
2146 | | // format 8: RGB, with 8 bits per colour |
2147 | 1.84k | else if (color_format == 8) |
2148 | 776 | { |
2149 | 776 | size_t i = 0; |
2150 | 37.3k | for (unsigned long y = 0; y < height; y++) |
2151 | 381k | for (unsigned long x = 0; x < width; x++, i++) |
2152 | 344k | { |
2153 | 344k | const libwpg::WPGColor color(buffer[3*i] & 0xff, buffer[3*i+1] & 0xff, buffer[3*i+2] & 0xff); |
2154 | 344k | bitmap.setPixel((int) x, (int) y, color); |
2155 | 344k | } |
2156 | | |
2157 | 776 | propList.insert("office:binary-data", bitmap.getDIB()); |
2158 | 776 | m_painter->drawGraphicObject(propList); |
2159 | 776 | } |
2160 | | // format 9: RGBA, with 8 bits per colour |
2161 | 1.07k | else if (color_format == 9) |
2162 | 138 | { |
2163 | 138 | size_t i = 0; |
2164 | 4.89k | for (unsigned long y = 0; y < height; y++) |
2165 | 18.0k | for (unsigned long x = 0; x < width; x++, i++) |
2166 | 13.2k | { |
2167 | 13.2k | const libwpg::WPGColor color(buffer[4*i], buffer[4*i+1] & 0xff, buffer[4*i+2] & 0xff, buffer[4*i+3] & 0xff); |
2168 | 13.2k | bitmap.setPixel((int) x, (int) y, color); |
2169 | 13.2k | } |
2170 | | |
2171 | 138 | propList.insert("office:binary-data", bitmap.getDIB()); |
2172 | 138 | m_painter->drawGraphicObject(propList); |
2173 | 138 | } |
2174 | 932 | else if (color_format == 12) |
2175 | 517 | { |
2176 | 517 | size_t i = 0; |
2177 | 52.2k | for (unsigned long y = 0; y < height; y++) |
2178 | 172k | for (unsigned long x = 0; x < width; x++, i++) |
2179 | 120k | { |
2180 | | |
2181 | 120k | const libwpg::WPGColor color(buffer[i], buffer[i], buffer[i]); |
2182 | 120k | bitmap.setPixel((int) x, (int) y, color); |
2183 | 120k | } |
2184 | | |
2185 | 517 | propList.insert("office:binary-data", bitmap.getDIB()); |
2186 | 517 | m_painter->drawGraphicObject(propList); |
2187 | 517 | } |
2188 | | |
2189 | 6.35k | } |
2190 | | |
2191 | | void WPG2Parser::handleObjectCapsule() |
2192 | 4.21k | { |
2193 | 4.21k | if (!m_graphicsStarted) |
2194 | 458 | return; |
2195 | 3.75k | ObjectCharacterization objCh; |
2196 | 3.75k | parseCharacterization(&objCh); |
2197 | 3.75k | m_matrix = objCh.matrix; |
2198 | | |
2199 | 3.75k | long x1 = (m_doublePrecision) ? readS32() : readS16(); |
2200 | 3.75k | long y1 = (m_doublePrecision) ? readS32() : readS16(); |
2201 | 3.75k | long x2 = (m_doublePrecision) ? readS32() : readS16(); |
2202 | 3.75k | long y2 = (m_doublePrecision) ? readS32() : readS16(); |
2203 | 3.75k | transformXY(x1,y1); |
2204 | 3.75k | transformXY(x2,y2); |
2205 | | |
2206 | 3.75k | long xs1 = (x1 <= x2) ? x1 : x2; |
2207 | 3.75k | long xs2 = (x1 <= x2) ? x2 : x1; |
2208 | 3.75k | long ys1 = (y1 <= y2) ? y1 : y2; |
2209 | 3.75k | long ys2 = (y1 <= y2) ? y2 : y1; |
2210 | | |
2211 | 3.75k | m_binaryData.x1 = toDouble(xs1) / m_xres; |
2212 | 3.75k | m_binaryData.y1 = toDouble(ys1) / m_yres; |
2213 | 3.75k | m_binaryData.x2 = toDouble(xs2) / m_xres; |
2214 | 3.75k | m_binaryData.y2 = toDouble(ys2) / m_yres; |
2215 | | |
2216 | 3.75k | unsigned long numDescriptions = readU16(); |
2217 | | |
2218 | 3.75k | m_binaryData.mimeTypes.clear(); |
2219 | 3.75k | m_binaryData.mimeTypes.reserve(numDescriptions); |
2220 | | |
2221 | 3.75k | static const char* const mimeTypesMap[] = |
2222 | 3.75k | { |
2223 | 3.75k | "", // 0 |
2224 | 3.75k | "", // "image/x-wpg", |
2225 | 3.75k | "", // "image/x-wpg", |
2226 | 3.75k | "", |
2227 | 3.75k | "", |
2228 | 3.75k | "", // 5 |
2229 | 3.75k | "image/bmp", |
2230 | 3.75k | "image/cgm", |
2231 | 3.75k | "", |
2232 | 3.75k | "image/x-dxf", |
2233 | 3.75k | "image/x-eps", // 0xA |
2234 | 3.75k | "", |
2235 | 3.75k | "image/gif", |
2236 | 3.75k | "application/vnd.hp-hpgl", |
2237 | 3.75k | "", |
2238 | 3.75k | "", // 0xF |
2239 | 3.75k | "", // 0x10 |
2240 | 3.75k | "", |
2241 | 3.75k | "", |
2242 | 3.75k | "image/x-pcx ", |
2243 | 3.75k | "image/x-lotus-pic", |
2244 | 3.75k | "", // Ox15 |
2245 | 3.75k | "", |
2246 | 3.75k | "image/x-quicktime", |
2247 | 3.75k | "", |
2248 | 3.75k | "application/x-postscript", |
2249 | 3.75k | "", // 0x1A |
2250 | 3.75k | "", |
2251 | 3.75k | "image/x-targa", |
2252 | 3.75k | "image/tiff", |
2253 | 3.75k | "", |
2254 | 3.75k | "image/wmf", // 0x1f |
2255 | 3.75k | "", // 0x20 |
2256 | 3.75k | "", |
2257 | 3.75k | "", |
2258 | 3.75k | "", |
2259 | 3.75k | "", |
2260 | 3.75k | "image/png", |
2261 | 3.75k | "image/gif" // 0x26 |
2262 | 3.75k | }; |
2263 | | |
2264 | 34.2k | for (unsigned long i = 0; m_input->tell() <= m_recordEnd && !m_input->isEnd() && i < numDescriptions; i++) |
2265 | 30.5k | { |
2266 | 30.5k | unsigned char description = readU8(); |
2267 | 30.5k | if (description < 0x27) |
2268 | 28.4k | m_binaryData.mimeTypes.push_back(librevenge::RVNGString(mimeTypesMap[description])); |
2269 | 30.5k | m_input->seek(7, librevenge::RVNG_SEEK_CUR); |
2270 | 30.5k | } |
2271 | | |
2272 | 3.75k | m_binaryData.objectIndex = 0; |
2273 | | |
2274 | 3.75k | WPG_DEBUG_MSG((" x1 : %li\n", x1)); |
2275 | 3.75k | WPG_DEBUG_MSG((" y1 : %li\n", y1)); |
2276 | 3.75k | WPG_DEBUG_MSG((" x2 : %li\n", x2)); |
2277 | 3.75k | WPG_DEBUG_MSG((" y2 : %li\n", y2)); |
2278 | 3.75k | WPG_DEBUG_MSG(("numDescriptions : %li\n", (long) numDescriptions)); |
2279 | 3.75k | } |
2280 | | |
2281 | | void WPG2Parser::handleObjectImage() |
2282 | 19.7k | { |
2283 | 19.7k | if (!m_graphicsStarted) |
2284 | 552 | return; |
2285 | 19.2k | if ((unsigned long)m_binaryData.objectIndex >= m_binaryData.mimeTypes.size()) |
2286 | 5.51k | return; |
2287 | 13.7k | unsigned accessoryDataLength = readU16(); |
2288 | 13.7k | m_input->seek((long) accessoryDataLength, librevenge::RVNG_SEEK_CUR); |
2289 | | |
2290 | 13.7k | librevenge::RVNGPropertyList propList; |
2291 | 13.7k | propList.insert("svg:x", (double)m_binaryData.x1); |
2292 | 13.7k | propList.insert("svg:y", (double)m_binaryData.y1); |
2293 | 13.7k | propList.insert("svg:width", (m_binaryData.x2 - m_binaryData.x1)); |
2294 | 13.7k | propList.insert("svg:height", (m_binaryData.y2 - m_binaryData.y1)); |
2295 | 13.7k | propList.insert("librevenge:mime-type", m_binaryData.mimeTypes[(size_t) m_binaryData.objectIndex]); |
2296 | | |
2297 | 13.7k | WPG_DEBUG_MSG(("Image Object Mime Type : %s\n", propList["librevenge:mime-type"]->getStr().cstr())); |
2298 | | |
2299 | 13.7k | librevenge::RVNGBinaryData binaryData; |
2300 | 13.7k | if (!m_input->isEnd() && m_input->tell() <= m_recordEnd) |
2301 | 79 | { |
2302 | 79 | unsigned long numBytes = 0; |
2303 | 79 | const unsigned char *const data = m_input->read(m_recordEnd - m_input->tell(), numBytes); |
2304 | 79 | binaryData = librevenge::RVNGBinaryData(data, numBytes); |
2305 | 79 | } |
2306 | 13.7k | WPG_DEBUG_MSG((" Image Object Size : %li\n", (unsigned long)binaryData.size())); |
2307 | | |
2308 | | // temporary for debug - dump the binary data (need to have write access in the current directory |
2309 | | #if DUMP_BINARY_DATA |
2310 | | std::ostringstream filename; |
2311 | | filename << "binarydump" << m_binaryId++ << ".bin"; |
2312 | | FILE *f = fopen(filename.str().c_str(), "wb"); |
2313 | | if (f) |
2314 | | { |
2315 | | const char *tmpBinaryBuffer = binaryData.getDataBuffer(); |
2316 | | unsigned long tmpBufferSize = binaryData.size(); |
2317 | | for (unsigned long k = 0; k < tmpBufferSize; k++) |
2318 | | fprintf(f, "%c",tmpBinaryBuffer[k]); |
2319 | | fclose(f); |
2320 | | } |
2321 | | #endif |
2322 | | |
2323 | | |
2324 | 13.7k | propList.insert("office:binary-data", binaryData); |
2325 | 13.7k | m_painter->drawGraphicObject(propList); |
2326 | 13.7k | m_binaryData.objectIndex++; |
2327 | 13.7k | } |
2328 | | |
2329 | | void WPG2Parser::handleTextLine() |
2330 | 29.6k | { |
2331 | 29.6k | if (!m_graphicsStarted) |
2332 | 484 | return; |
2333 | 29.1k | ObjectCharacterization objCh; |
2334 | 29.1k | parseCharacterization(&objCh); |
2335 | 29.1k | m_matrix = objCh.matrix; |
2336 | | |
2337 | 29.1k | unsigned short textFlags = readU16(); |
2338 | 29.1k | long x = (m_doublePrecision) ? readS32() : readS16(); |
2339 | 29.1k | long y = (m_doublePrecision) ? readS32() : readS16(); |
2340 | 29.1k | transformXY(x,y); |
2341 | | |
2342 | 29.1k | unsigned char horizontalAlignment = readU8(); |
2343 | 29.1k | unsigned char verticalAlignment = readU8(); |
2344 | | |
2345 | 29.1k | double baseLineAngle = fixedPointToDouble(readU32()); |
2346 | | |
2347 | 29.1k | WPG_DEBUG_MSG((" text flags : 0x%.4x\n", textFlags)); |
2348 | 29.1k | WPG_DEBUG_MSG((" x : %li\n", x)); |
2349 | 29.1k | WPG_DEBUG_MSG((" y : %li\n", y)); |
2350 | 29.1k | WPG_DEBUG_MSG((" horizontal alignment : 0x%.2x\n", horizontalAlignment)); |
2351 | 29.1k | WPG_DEBUG_MSG((" vertical alignment : 0x%.2x\n", verticalAlignment)); |
2352 | 29.1k | WPG_DEBUG_MSG((" baseline angle : %.4f\n", baseLineAngle)); |
2353 | | |
2354 | 29.1k | m_textData.x1 = toDouble(x)/m_xres; |
2355 | 29.1k | m_textData.y1 = toDouble(y)/m_yres; |
2356 | 29.1k | m_textData.x2 = toDouble(x)/m_xres; |
2357 | 29.1k | m_textData.y2 = toDouble(y)/m_yres; |
2358 | 29.1k | m_textData.flags = textFlags; |
2359 | 29.1k | m_textData.horAlign = horizontalAlignment; |
2360 | 29.1k | m_textData.vertAlign = verticalAlignment; |
2361 | 29.1k | m_textData.baseLineAngle = baseLineAngle; |
2362 | | |
2363 | 29.1k | m_drawTextData = true; |
2364 | 29.1k | } |
2365 | | |
2366 | | void WPG2Parser::handleTextBlock() |
2367 | 2.39k | { |
2368 | 2.39k | if (!m_graphicsStarted) |
2369 | 230 | return; |
2370 | 2.16k | ObjectCharacterization objCh; |
2371 | 2.16k | parseCharacterization(&objCh); |
2372 | 2.16k | m_matrix = objCh.matrix; |
2373 | | |
2374 | 2.16k | long x1 = (m_doublePrecision) ? readS32() : readS16(); |
2375 | 2.16k | long y1 = (m_doublePrecision) ? readS32() : readS16(); |
2376 | 2.16k | long x2 = (m_doublePrecision) ? readS32() : readS16(); |
2377 | 2.16k | long y2 = (m_doublePrecision) ? readS32() : readS16(); |
2378 | 2.16k | transformXY(x1,y1); |
2379 | 2.16k | transformXY(x2,y2); |
2380 | | |
2381 | 2.16k | long xs1 = (x1 <= x2) ? x1 : x2; |
2382 | 2.16k | long xs2 = (x1 <= x2) ? x2 : x1; |
2383 | 2.16k | long ys1 = (y1 <= y2) ? y1 : y2; |
2384 | 2.16k | long ys2 = (y1 <= y2) ? y2 : y1; |
2385 | | |
2386 | 2.16k | WPG_DEBUG_MSG((" x1 : %li\n", xs1)); |
2387 | 2.16k | WPG_DEBUG_MSG((" y1 : %li\n", ys1)); |
2388 | 2.16k | WPG_DEBUG_MSG((" x2 : %li\n", xs2)); |
2389 | 2.16k | WPG_DEBUG_MSG((" y2 : %li\n", ys2)); |
2390 | | |
2391 | 2.16k | m_textData.x1 = toDouble(xs1)/m_xres; |
2392 | 2.16k | m_textData.y1 = toDouble(ys1)/m_yres; |
2393 | 2.16k | m_textData.x2 = toDouble(xs2)/m_xres; |
2394 | 2.16k | m_textData.y2 = toDouble(ys2)/m_yres; |
2395 | 2.16k | m_textData.flags = 0; |
2396 | 2.16k | m_textData.horAlign = 0; |
2397 | 2.16k | m_textData.vertAlign = 0; |
2398 | 2.16k | m_textData.baseLineAngle = 0.0; |
2399 | | |
2400 | 2.16k | m_drawTextData = false; |
2401 | 2.16k | } |
2402 | | |
2403 | | void WPG2Parser::handleTextPath() |
2404 | 1.05k | { |
2405 | 1.05k | if (!m_graphicsStarted) |
2406 | 196 | return; |
2407 | | |
2408 | 862 | m_drawTextData = false; |
2409 | 862 | } |
2410 | | |
2411 | | void WPG2Parser::handleTextData() |
2412 | 17.6k | { |
2413 | 17.6k | if (!m_graphicsStarted) |
2414 | 242 | return; |
2415 | 17.3k | if (!m_drawTextData) |
2416 | 482 | return; |
2417 | 16.8k | if (m_input->isEnd() || m_input->tell() >= m_recordEnd) |
2418 | 686 | return; |
2419 | | |
2420 | 16.2k | unsigned long numBytes = 0; |
2421 | 16.2k | const unsigned char *const data = m_input->read(m_recordEnd - m_input->tell(), numBytes); |
2422 | 16.2k | librevenge::RVNGBinaryData textData(data, numBytes); |
2423 | | |
2424 | 16.2k | WPGTextDataHandler handler(m_painter); |
2425 | 16.2k | librevenge::RVNGPropertyList propList; |
2426 | | |
2427 | 16.2k | propList.insert("svg:x", (double)m_textData.x1); |
2428 | 16.2k | propList.insert("svg:y", (double)m_textData.y1); |
2429 | 16.2k | if ((m_textData.x1 < m_textData.x2 || m_textData.x1 > m_textData.x2) && |
2430 | 0 | (m_textData.y1 < m_textData.y2 || m_textData.y1 > m_textData.y2)) |
2431 | 0 | { |
2432 | 0 | propList.insert("svg:width", (m_textData.x2 - m_textData.x1)); |
2433 | 0 | propList.insert("svg:height", (m_textData.y2 - m_textData.y1)); |
2434 | 0 | } |
2435 | | |
2436 | 16.2k | m_painter->startTextObject(propList); |
2437 | | |
2438 | 16.2k | WPDocument::parseSubDocument(const_cast<librevenge::RVNGInputStream *>(textData.getDataStream()), &handler, WPD_FILE_FORMAT_WP6); |
2439 | | |
2440 | 16.2k | m_painter->endTextObject(); |
2441 | | |
2442 | 16.2k | m_drawTextData = false; |
2443 | 16.2k | } |
2444 | | |
2445 | | void WPG2Parser::resetPalette() |
2446 | 13.3k | { |
2447 | 13.3k | m_colorPalette.clear(); |
2448 | 3.42M | for (int i=0; i<256; i++) |
2449 | 3.40M | { |
2450 | 3.40M | unsigned char red = defaultWPG2PaletteRed[i]; |
2451 | 3.40M | unsigned char green = defaultWPG2PaletteGreen[i]; |
2452 | 3.40M | unsigned char blue = defaultWPG2PaletteBlue[i]; |
2453 | 3.40M | libwpg::WPGColor color(red, green, blue); |
2454 | 3.40M | m_colorPalette[i] = color; |
2455 | 3.40M | } |
2456 | 13.3k | } |
2457 | | |
2458 | | unsigned int WPG2Parser::getRemainingRecordLength() const |
2459 | 98.8k | { |
2460 | 98.8k | if (m_recordEnd < m_input->tell()) |
2461 | 65.1k | return 0; |
2462 | 33.7k | return static_cast<unsigned int>(m_recordEnd - m_input->tell() + 1); |
2463 | 98.8k | } |
2464 | | |
2465 | | bool WPG2Parser::checkRLESize(const unsigned bytes) const |
2466 | 7.24k | { |
2467 | | // The upper bound of the number of bytes encoded in this RLE record |
2468 | 7.24k | const unsigned long maxSize = ((getRemainingRecordLength() + 1) / 2) * 256; |
2469 | 7.24k | return bytes < maxSize; |
2470 | 7.24k | } |
2471 | | |
2472 | | double WPG2Parser::toDouble(long x) const |
2473 | 15.0M | { |
2474 | 15.0M | return m_doublePrecision ? double(x)/65536.0 : double(x); |
2475 | 15.0M | } |
2476 | | |
2477 | | void WPG2Parser::transformXY(long &x, long &y) const |
2478 | 1.29M | { |
2479 | 1.29M | m_matrix.transform(x,y); |
2480 | 1.29M | x = safeSubtract(x, m_xofs); |
2481 | 1.29M | y = safeSubtract(y, m_yofs); |
2482 | 1.29M | y = safeSubtract(m_height, y); |
2483 | 1.29M | } |
2484 | | |
2485 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |