1 /* libwpg
2 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
3 * Copyright (C) 2005 Fridrich Strba (fridrich.strba@bluewin.ch)
4 * Copyright (C) 2004 Marc Oude Kotte (marc@solcon.nl)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02111-1301 USA
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 "WPG1Parser.h"
29 #include "WPGPaintInterface.h"
30 #include "libwpg_utils.h"
31
32 static const unsigned char defaultWPG1PaletteRed[] = {
33 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F,
34 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
35 0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
36 0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
37 0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
38 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
41 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
42 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
43 0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
45 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
46 0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
47 0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
50 0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
51 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
52 0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
53 0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
54 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
55 0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
56 0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
59 0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
60 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
61 0x3C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
62 0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
63 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x2C,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 };
66
67 static const unsigned char defaultWPG1PaletteGreen[] = {
68 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x3F, 0x7F,
69 0xC0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
70 0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
71 0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
74 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
75 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
76 0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
77 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
78 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
79 0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
80 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
83 0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
84 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
85 0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
86 0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
87 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
88 0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
89 0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
90 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
92 0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
93 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
94 0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
95 0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
96 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
97 0x3C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
98 0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 };
101
102 static const unsigned char defaultWPG1PaletteBlue[] = {
103 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x7F,
104 0xC0, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
105 0x00, 0x14, 0x20, 0x2C, 0x38, 0x45, 0x51, 0x61,
106 0x71, 0x82, 0x92, 0xA2, 0xB6, 0xCB, 0xE3, 0xFF,
107 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7D, 0x41,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x41, 0x7D, 0xBE, 0xFF, 0xFF, 0xFF, 0xFF,
110 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xBE, 0x9E,
111 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
112 0x7D, 0x9E, 0xBE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF,
113 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB, 0xDB, 0xC7,
114 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
115 0xB6, 0xC7, 0xDB, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF,
116 0x71, 0x71, 0x71, 0x71, 0x71, 0x55, 0x38, 0x1C,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x1C, 0x38, 0x55, 0x71, 0x71, 0x71, 0x71,
119 0x71, 0x71, 0x71, 0x71, 0x71, 0x61, 0x55, 0x45,
120 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
121 0x38, 0x45, 0x55, 0x61, 0x71, 0x71, 0x71, 0x71,
122 0x71, 0x71, 0x71, 0x71, 0x71, 0x69, 0x61, 0x59,
123 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51,
124 0x51, 0x59, 0x61, 0x69, 0x71, 0x71, 0x71, 0x71,
125 0x41, 0x41, 0x41, 0x41, 0x41, 0x30, 0x20, 0x10,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x10, 0x20, 0x30, 0x41, 0x41, 0x41, 0x41,
128 0x41, 0x41, 0x41, 0x41, 0x41, 0x38, 0x30, 0x28,
129 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
130 0x20, 0x28, 0x30, 0x38, 0x41, 0x41, 0x41, 0x41,
131 0x41, 0x41, 0x41, 0x41, 0x41, 0x3C, 0x34, 0x30,
132 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C,
133 0x2C, 0x30, 0x34, 0x3C, 0x41, 0x41, 0x41, 0x41,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 };
136
137
WPG1Parser(WPXInputStream * input,libwpg::WPGPaintInterface * painter)138 WPG1Parser::WPG1Parser(WPXInputStream *input, libwpg::WPGPaintInterface* painter):
139 WPGXParser(input, painter),
140 m_recordLength(0), m_recordEnd(0),
141 m_success(true), m_exit(false), m_graphicsStarted(false),
142 m_width(0), m_height(0),
143 m_pen(libwpg::WPGPen()), m_brush(libwpg::WPGBrush())
144 {
145 }
146
parse()147 bool WPG1Parser::parse()
148 {
149 typedef void (WPG1Parser::*Method)();
150
151 struct RecordHandler
152 {
153 int type;
154 const char *name;
155 Method handler;
156 };
157
158 static const struct RecordHandler handlers[] =
159 {
160 { 0x01, "Fill Attributes", &WPG1Parser::handleFillAttributes },
161 { 0x02, "Line Attributes", &WPG1Parser::handleLineAttributes },
162 { 0x03, "Marker Atttibutes", nullptr },
163 { 0x04, "Polymarker", nullptr },
164 { 0x05, "Line", &WPG1Parser::handleLine },
165 { 0x06, "Polyline", &WPG1Parser::handlePolyline },
166 { 0x07, "Rectangle", &WPG1Parser::handleRectangle },
167 { 0x08, "Polygon", &WPG1Parser::handlePolygon },
168 { 0x09, "Ellipse", &WPG1Parser::handleEllipse },
169 { 0x0a, "Reserved", nullptr },
170 { 0x0b, "Bitmap (Type 1)", &WPG1Parser::handleBitmapTypeOne },
171 { 0x0c, "Graphics Text (Type 1)", nullptr },
172 { 0x0d, "Grephics Text Attributes", nullptr },
173 { 0x0e, "Colormap", &WPG1Parser::handleColormap },
174 { 0x0f, "Start WPG", &WPG1Parser::handleStartWPG },
175 { 0x10, "End WPG", &WPG1Parser::handleEndWPG },
176 { 0x11, "Postscript Data (Type 1)", &WPG1Parser::handlePostscriptTypeOne },
177 { 0x12, "Output Attributes", nullptr },
178 { 0x13, "Curved Polyline", &WPG1Parser::handleCurvedPolyline },
179 { 0x14, "Bitmap (Type 2)", &WPG1Parser::handleBitmapTypeTwo },
180 { 0x15, "Start Figure", nullptr },
181 { 0x16, "Start Chart", nullptr },
182 { 0x17, "Planperfect Data", nullptr },
183 { 0x18, "Graphics Text (Type 2)", nullptr },
184 { 0x19, "Start WPG (Type 2)", nullptr },
185 { 0x1a, "Graphics Text (Type 3)", nullptr },
186 { 0x1b, "Postscript Data (Type 2)", &WPG1Parser::handlePostscriptTypeTwo },
187 { 0x00, nullptr, nullptr } // end marker
188 };
189
190 // initialization
191 m_recordLength = 0;
192 m_recordEnd = 0;
193 m_success = true;
194 m_exit = false;
195 m_graphicsStarted = false;
196
197 // default style
198 m_pen.foreColor = libwpg::WPGColor(0,0,0);
199 m_pen.backColor = libwpg::WPGColor(0,0,0);
200 m_pen.width = 0.001;
201 m_pen.height = 0.001;
202 m_pen.solid = true;
203 m_pen.dashArray = libwpg::WPGDashArray();
204 m_brush.foreColor = libwpg::WPGColor(0,0,0);
205 m_brush.backColor = libwpg::WPGColor(0,0,0);
206 resetPalette();
207
208 while(!m_input->atEOS())
209 {
210 #ifdef DEBUG
211 long recordPos = m_input->tell();
212 #endif
213 int recordType = readU8();
214 if (recordType == 0)
215 break;
216 m_recordLength = readVariableLengthInteger();
217 m_recordEnd = m_input->tell() + m_recordLength - 1;
218
219 // search function to handler this record
220 int index = -1;
221 for(int i = 0; (index < 0) && handlers[i].name; i++)
222 if(handlers[i].type == recordType)
223 index = i;
224
225 WPG_DEBUG_MSG(("\n"));
226 if(index < 0)
227 WPG_DEBUG_MSG(("Unknown record type 0x%02x at %li size %d\n",
228 recordType, recordPos, m_recordLength));
229 else
230 {
231 Method recordHandler = handlers[index].handler;
232 if(!recordHandler)
233 WPG_DEBUG_MSG(("Record '%s' (ignored) type 0x%02x at %li size %d\n",
234 handlers[index].name, recordType, recordPos, m_recordLength));
235 else
236 {
237 WPG_DEBUG_MSG(("Record '%s' type 0x%02x at %li size %d\n",
238 handlers[index].name, recordType, recordPos, m_recordLength));
239
240 // invoke the handler for this record
241 (this->*recordHandler)();
242 }
243 }
244
245 //if(m_input->tell() > m_recordEnd+1)
246 {
247 //WPG_DEBUG_MSG(("Record 0x%x consumes more bytes than necessary!\n", recordType));
248 WPG_DEBUG_MSG(("Current stream position: %li\n", m_input->tell()));
249 }
250
251 if(m_exit) break;
252
253 m_input->seek(m_recordEnd+1, WPX_SEEK_SET);
254 }
255
256 if (!m_exit)
257 handleEndWPG();
258
259 return m_success;
260 }
261
handleStartWPG()262 void WPG1Parser::handleStartWPG()
263 {
264 if (m_graphicsStarted)
265 {
266 handleEndWPG();
267 return;
268 }
269 // unsigned char version = readU8();
270 // unsigned char bitFlags = readU8();
271 m_input->seek(2, WPX_SEEK_CUR);
272 m_width = readU16();
273 m_height = readU16();
274
275 double width = (double)m_width / 1200.0;
276 double height = (double)m_height / 1200.0;
277 m_painter->startGraphics(width, height);
278 m_graphicsStarted = true;
279
280 WPG_DEBUG_MSG(("StartWPG\n"));
281 }
282
handleEndWPG()283 void WPG1Parser::handleEndWPG()
284 {
285 if (!m_graphicsStarted)
286 return;
287 m_painter->endGraphics();
288 m_exit = true;
289
290 WPG_DEBUG_MSG(("EndWPG\n"));
291 }
292
handleColormap()293 void WPG1Parser::handleColormap()
294 {
295 if (!m_graphicsStarted)
296 return;
297 unsigned startIndex = readU16();
298 unsigned numEntries = readU16();
299 if (startIndex > 255 || numEntries > 256 || startIndex + numEntries > 256)
300 return;
301
302 WPG_DEBUG_MSG(("Colormap\n"));
303 for(unsigned int i = 0; i < numEntries; i++)
304 {
305 libwpg::WPGColor color;
306 color.red = readU8();
307 color.green = readU8();
308 color.blue = readU8();
309 m_colorPalette[startIndex+i] = color;
310 WPG_DEBUG_MSG(("Index#%d: RGB %d %d %d\n", startIndex+i, color.red, color.green, color.blue));
311 }
312 }
313
handleFillAttributes()314 void WPG1Parser::handleFillAttributes()
315 {
316 if (!m_graphicsStarted)
317 return;
318 unsigned char style = readU8();
319 unsigned char color = readU8();
320
321 if(style == 0)
322 m_brush.style = libwpg::WPGBrush::NoBrush;
323 if(style == 1)
324 m_brush.style = libwpg::WPGBrush::Solid;
325
326 m_brush.foreColor = m_colorPalette[color];
327
328 WPG_DEBUG_MSG(("Fill Attributes\n"));
329 WPG_DEBUG_MSG((" Fill style: %d\n", style));
330 WPG_DEBUG_MSG((" Fill color index: %d\n", color));
331 }
332
handleLineAttributes()333 void WPG1Parser::handleLineAttributes()
334 {
335 if (!m_graphicsStarted)
336 return;
337 unsigned char style = readU8();
338 unsigned char color = readU8();
339 unsigned int width = readU16();
340
341 m_pen.solid = style != 0;
342 m_pen.foreColor = m_colorPalette[color];
343 if (!width && m_pen.solid)
344 m_pen.width = 0.001;
345 else
346 m_pen.width = (double)width / 1200.0;
347
348 WPG_DEBUG_MSG(("Line Attributes\n"));
349 WPG_DEBUG_MSG((" Line style: %d\n", style));
350 WPG_DEBUG_MSG((" Line color index: %d\n", color));
351 WPG_DEBUG_MSG((" Line width: %d\n", width));
352 }
353
handleLine()354 void WPG1Parser::handleLine()
355 {
356 if (!m_graphicsStarted)
357 return;
358 int sx = readS16();
359 int sy = readS16();
360 int ex = readS16();
361 int ey = readS16();
362
363 libwpg::WPGPointArray points;
364 points.add(libwpg::WPGPoint((double)sx/1200.0, (double)(m_height-sy)/1200.0));
365 points.add(libwpg::WPGPoint((double)ex/1200.0, (double)(m_height-ey)/1200.0));
366
367 m_painter->setBrush(m_brush);
368 m_painter->setPen(m_pen);
369 m_painter->drawPolygon(points, true);
370
371 WPG_DEBUG_MSG(("Line\n"));
372 WPG_DEBUG_MSG((" Starting point: %d,%d\n", sx, sy));
373 WPG_DEBUG_MSG((" End point: %d,%d\n", ex, ey));
374 }
375
handlePolyline()376 void WPG1Parser::handlePolyline()
377 {
378 if (!m_graphicsStarted)
379 return;
380 unsigned int count = readU16();
381
382 libwpg::WPGPointArray points;
383 for(unsigned int i = 0; i < count; i++ )
384 {
385 long x = readS16();
386 long y = readS16();
387 points.add(libwpg::WPGPoint((double)x/1200.0, (double)(m_height-y)/1200.0));
388 }
389
390 m_painter->setBrush(libwpg::WPGBrush()); // not filled
391 m_painter->setPen(m_pen);
392 m_painter->drawPolygon(points, false);
393
394 WPG_DEBUG_MSG(("Polyline\n"));
395 }
396
handleRectangle()397 void WPG1Parser::handleRectangle()
398 {
399 if (!m_graphicsStarted)
400 return;
401 int x = readS16();
402 int y = readS16();
403 int w = readS16();
404 int h = readS16();
405
406 libwpg::WPGRect rect;
407 rect.x1 = (double)x/1200.0;
408 // in WPG, we have the coordinate of lower left point, in SVG-ish coordinates we have to get upper left
409 rect.y1 = (double)(m_height - h - y)/1200.0;
410 rect.x2 = rect.x1 + (double)w/1200.0;
411 rect.y2 = rect.y1 + (double)h/1200.0;
412
413 m_painter->setBrush(m_brush);
414 m_painter->setPen(m_pen);
415 m_painter->drawRectangle(rect, 0, 0);
416
417 WPG_DEBUG_MSG(("Line\n"));
418 WPG_DEBUG_MSG((" Corner point: %d,%d\n", x, y));
419 WPG_DEBUG_MSG((" Width: %d\n", w));
420 WPG_DEBUG_MSG((" Height: %d\n", h));
421 }
422
handlePolygon()423 void WPG1Parser::handlePolygon()
424 {
425 if (!m_graphicsStarted)
426 return;
427 unsigned int count = readU16();
428
429 libwpg::WPGPointArray points;
430 for(unsigned int i = 0; i < count; i++ )
431 {
432 long x = readS16();
433 long y = readS16();
434 points.add(libwpg::WPGPoint((double)x/1200.0, (double)(m_height-y)/1200.0));
435 }
436
437 m_painter->setBrush(m_brush);
438 m_painter->setPen(m_pen);
439 m_painter->drawPolygon(points, true);
440
441 WPG_DEBUG_MSG(("Polygon\n"));
442 }
443
handleEllipse()444 void WPG1Parser::handleEllipse()
445 {
446 if (!m_graphicsStarted)
447 return;
448 int cx = readS16();
449 int cy = readS16();
450 int rx = readS16();
451 int ry = readS16();
452 readS16();
453 readS16();
454 readS16();
455 readS16();
456 /*
457 int rotation = readS16();
458 int beginAngle = readS16();
459 int endAngle = readS16();
460 unsigned flags = readU16();
461 */
462 libwpg::WPGPoint center;
463 center.x = (double)cx/1200.0;
464 center.y = (double)(m_height-cy)/1200.0;
465
466 double radx = (double)rx/1200.0;
467 double rady = (double)ry/1200.0;
468
469 m_painter->setBrush(m_brush);
470 m_painter->setPen(m_pen);
471 m_painter->drawEllipse(center, radx, rady);
472
473 WPG_DEBUG_MSG(("Ellipse\n"));
474 WPG_DEBUG_MSG((" Center point: %d,%d\n", cx, cy));
475 WPG_DEBUG_MSG((" Radius x: %d\n", rx));
476 WPG_DEBUG_MSG((" Radius y: %d\n", ry));
477 }
478
handleCurvedPolyline()479 void WPG1Parser::handleCurvedPolyline()
480 {
481 if (!m_graphicsStarted)
482 return;
483 readU32();
484 unsigned int count = readU16();
485 if (!count)
486 return;
487 libwpg::WPGPath path;
488 path.closed = false;
489 path.framed = true;
490 path.filled = true;
491 long xInitial = readS16();
492 long yInitial = readS16();
493 path.moveTo(libwpg::WPGPoint((double)xInitial/1200.0, (double)(m_height-yInitial)/1200.0));
494 for (unsigned i = 1; i < (count-1)/3; i++)
495 {
496 long xControl1 = readS16();
497 long yControl1 = readS16();
498 long xControl2 = readS16();
499 long yControl2 = readS16();
500 long xCoordinate = readS16();
501 long yCoordinate = readS16();
502 path.curveTo(libwpg::WPGPoint((double)xControl1/1200.0, (double)(m_height-yControl1)/1200.0),
503 libwpg::WPGPoint((double)xControl2/1200.0, (double)(m_height-yControl2)/1200.0),
504 libwpg::WPGPoint((double)xCoordinate/1200.0, (double)(m_height-yCoordinate)/1200.0));
505 }
506
507 m_painter->setBrush(path.closed ? m_brush : libwpg::WPGBrush());
508 m_painter->setPen(m_pen);
509 m_painter->drawPath(path);
510
511 WPG_DEBUG_MSG(("Curved Polyline\n"));
512 }
513
decodeRLE(std::vector<unsigned char> & buffer,unsigned width,unsigned height,unsigned depth)514 void WPG1Parser::decodeRLE(std::vector<unsigned char>& buffer, unsigned width, unsigned height, unsigned depth)
515 {
516 buffer.clear();
517
518 // This are the known depth values for WPG1, no point to try to decode others since they are likely to indicate corruption
519 if (depth != 8 && depth != 4 && depth != 2 && depth != 1)
520 return;
521
522 // round to the next byte
523 unsigned scanline_width = (width * depth + 7)/8;
524 unsigned tmpBufferSize = scanline_width * height;
525 WPG_DEBUG_MSG(("Scanline width: %d\n", scanline_width));
526 WPG_DEBUG_MSG(("Output size: %d\n", scanline_width * height));
527
528 WPG_DEBUG_MSG(("Decoding RLE data\n"));
529
530 buffer.reserve(tmpBufferSize);
531 while (m_input->tell() < m_recordEnd && !m_input->atEOS() && buffer.size() < tmpBufferSize)
532 {
533 unsigned char opcode = readU8();
534
535 if(opcode & 0x80)
536 {
537 // run of byte
538 int count = (int)(opcode & 0x7f);
539 unsigned char pixel = (count > 0) ? readU8() : 0xff;
540 if(count == 0)
541 count = (int)readU8();
542 for( ; count ; --count)
543 buffer.push_back( pixel );
544 }
545 else
546 {
547 int count = (int)(opcode & 0x7f);
548 if(count > 0)
549 {
550 // literal byte copy
551 for( ; count ; --count)
552 buffer.push_back( readU8() );
553 }
554 else
555 {
556 // copy entire scan line
557 count = (int)readU8();
558 if (buffer.size() < scanline_width )
559 {
560 WPG_DEBUG_MSG(("Cannot copy the scanline, not enough data %li\n", (long)buffer.size()));
561 break;
562 }
563 unsigned raster_source = buffer.size() - scanline_width;
564 for( ; count; --count)
565 for(unsigned r = 0; r < scanline_width ; r++)
566 {
567 unsigned char pixel = buffer[raster_source + r];
568 buffer.push_back( pixel );
569 }
570 }
571 }
572 }
573 WPG_DEBUG_MSG(("Finish decoding RLE data\n"));
574 WPG_DEBUG_MSG(("Buffer length: %li\n", (long)buffer.size()));
575
576 while (buffer.size() < tmpBufferSize)
577 buffer.push_back(0);
578 }
579
fillPixels(libwpg::WPGBitmap & bitmap,const unsigned char * buffer,unsigned width,unsigned height,unsigned depth)580 void WPG1Parser::fillPixels(libwpg::WPGBitmap& bitmap, const unsigned char* buffer, unsigned width, unsigned height, unsigned depth)
581 {
582 // sanity
583 if(!buffer)
584 return;
585
586 if (depth != 8 && depth != 4 && depth != 2 && depth != 1)
587 return;
588
589 // round to the next byte
590 unsigned scanline_width = (width * depth + 7)/8;
591
592 // 1-bit image: black and white
593 if(depth == 1)
594 {
595 libwpg::WPGColor black(0, 0, 0);
596 libwpg::WPGColor white(255, 255, 255);
597 for(unsigned y = 0; y < height; y++)
598 {
599 const unsigned char* buf = buffer + y * scanline_width;
600 for(unsigned x = 0; x < width; x++)
601 if(buf[x/8] & (0x80 >> (x & 7)))
602 bitmap.setPixel(x, y, white);
603 else
604 bitmap.setPixel(x, y, black);
605 }
606 }
607 // 2-bit image: 4-color bitmap (indexed)
608 else if(depth == 2)
609 {
610 unsigned i = 0;
611 for (unsigned y = 0; y < height; y++)
612 for (unsigned x = 0; x < width; x++, i++)
613 {
614 if ((x==0) && (i % 4 != 0))
615 i = (i/4 + 1) * 4;
616 unsigned index = ((buffer[i/4] & (0x03 << 2*(3 - (i % 4)))) >> 2*(3 - (i % 4)));
617 const libwpg::WPGColor& color = m_colorPalette[index];
618 bitmap.setPixel(x, y, color);
619 }
620 }
621 // 4 -bit image: 16-colour bitmap (indexed)
622 else if(depth == 4)
623 {
624 unsigned i = 0;
625 for (unsigned y = 0; y < height; y++)
626 for (unsigned x = 0; x < width; x++, i++)
627 {
628 if ((x==0) && (i % 2 != 0))
629 i = (i/2 + 1) * 2;
630 unsigned index = ((buffer[i/2] & (0x0f << 4*(1 - (i % 2)))) >> 4*(1 - (i % 2)));
631 const libwpg::WPGColor& color = m_colorPalette[index];
632 bitmap.setPixel(x, y, color);
633 }
634 }
635 // 8-bit image: 256-colour image (indexed)
636 else if(depth == 8)
637 {
638 for(unsigned y = 0; y < height; y++)
639 {
640 const unsigned char* buf = buffer + y * scanline_width;
641 for(unsigned x = 0; x < width; x++)
642 {
643 const libwpg::WPGColor& color = m_colorPalette[buf[x]];
644 bitmap.setPixel(x, y, color);
645 }
646 }
647
648 }
649
650 // debugging only
651 /* if(buffer && 0)
652 {
653 for(unsigned x = 0; x < width; x++)
654 for(unsigned y = 0; y < height; y++)
655 {
656 libwpg::WPGColor color = bitmap.pixel(x,y);
657 WPG_DEBUG_MSG((" pixel at %d, %d: %3d %3d %3d\n", x, y, color.red, color.green, color.blue));
658 }
659 }*/
660 }
661
handleBitmapTypeOne()662 void WPG1Parser::handleBitmapTypeOne()
663 {
664 if (!m_graphicsStarted)
665 return;
666 int width = readS16();
667 int height = readS16();
668 int depth = readS16();
669 int hres = readS16();
670 int vres = readS16();
671
672 WPG_DEBUG_MSG(("Bitmap\n"));
673 WPG_DEBUG_MSG((" Width: %d\n", width));
674 WPG_DEBUG_MSG((" Height: %d\n", height));
675 WPG_DEBUG_MSG((" Depth: %d\n", depth));
676 WPG_DEBUG_MSG(("Horizontal resolution: %d\n", hres));
677 WPG_DEBUG_MSG((" Vertical resolution: %d\n", vres));
678
679 // if this happens, likely corruption, bail out.
680 if (depth != 1 && depth != 2 && depth != 4 && depth != 8)
681 return;
682
683 // Sanity checks
684 if(hres <= 0)
685 hres = 1200;
686 if(vres <= 0)
687 vres = 1200;
688 if (width < 0)
689 width = 0;
690 if (height < 0)
691 height = 0;
692 if (depth < 0)
693 depth = 0;
694
695 // Bitmap Type 1 does not specify position
696 // Assume on the corner (0,0)
697 libwpg::WPGBitmap bitmap(width, height);
698 bitmap.rect.x1 = 0;
699 bitmap.rect.y1 = 0;
700 bitmap.rect.x2 = (double)width/(double)hres;
701 bitmap.rect.y2 = (double)height/(double)vres;
702
703 std::vector<unsigned char> buffer;
704 decodeRLE(buffer, width, height, depth);
705 if (!buffer.empty() && buffer.size() == (size_t)((width*depth + 7)/8)*height)
706 {
707 fillPixels(bitmap, &buffer[0], width, height, depth);
708 m_painter->drawBitmap(bitmap, hres, vres);
709 }
710 }
711
handleBitmapTypeTwo()712 void WPG1Parser::handleBitmapTypeTwo()
713 {
714 if (!m_graphicsStarted)
715 return;
716 int rotation = readS16();
717 int x1 = readS16();
718 int y1 = readS16();
719 int x2 = readS16();
720 int y2 = readS16();
721 int width = readS16();
722 int height = readS16();
723 int depth = readS16();
724 int hres = readS16();
725 int vres = readS16();
726
727 WPG_DEBUG_MSG(("Bitmap\n"));
728 WPG_DEBUG_MSG((" Rotation Angle: %d\n", rotation));
729 WPG_DEBUG_MSG((" Top left corner: %d,%d\n", x1, y1));
730 WPG_DEBUG_MSG((" Bottom right corner: %d,%d\n", x2, y2));
731 WPG_DEBUG_MSG((" Width: %d\n", width));
732 WPG_DEBUG_MSG((" Height: %d\n", height));
733 WPG_DEBUG_MSG((" Depth: %d\n", depth));
734 WPG_DEBUG_MSG(("Horizontal resolution: %d\n", hres));
735 WPG_DEBUG_MSG((" Vertical resolution: %d\n", vres));
736
737 // if this happens, likely corruption, bail out.
738 if (rotation < 0 || rotation > 359)
739 return;
740 if (depth != 1 && depth != 2 && depth != 4 && depth != 8)
741 return;
742
743 // Sanity checks
744 if(hres <= 0)
745 hres = 1200;
746 if(vres <= 0)
747 vres = 1200;
748 if (width < 0)
749 width = 0;
750 if (height < 0)
751 height = 0;
752 if (depth < 0)
753 depth = 0;
754
755 y1 = m_height - y1;
756 y2 = m_height - y2;
757
758 long xs1 = (x1 <= x2) ? x1 : x2;
759 long xs2 = (x1 <= x2) ? x2 : x1;
760 long ys1 = (y1 <= y2) ? y1 : y2;
761 long ys2 = (y1 <= y2) ? y2 : y1;
762 WPG_DEBUG_MSG(("%li %li %li %li\n", xs1, ys1, xs2, ys2));
763
764 libwpg::WPGBitmap bitmap(width, height);
765 bitmap.rect.x1 = (double)xs1/1200.0;
766 bitmap.rect.y1 = (double)(ys1)/1200.0;
767 bitmap.rect.x2 = (double)xs2/1200.0;
768 bitmap.rect.y2 = (double)(ys2)/1200.0;
769
770 std::vector<unsigned char> buffer;
771 decodeRLE(buffer, width, height, depth);
772 if (buffer.size() && buffer.size() == (size_t)((width*depth + 7)/8)*height)
773 {
774 fillPixels(bitmap, &buffer[0], width, height, depth);
775 m_painter->drawBitmap(bitmap, hres, vres);
776 }
777 }
778
handlePostscriptTypeOne()779 void WPG1Parser::handlePostscriptTypeOne()
780 {
781 if (!m_graphicsStarted)
782 return;
783 long x1 = readS16();
784 long y1 = readS16();
785 long x2 = readS16();
786 long y2 = readS16();
787 libwpg::WPGBinaryData data;
788 data.rect.x1 = (double)x1/72.0;
789 data.rect.y1 = (double)m_height/1200.0 - (double)y1/72.0;
790 data.rect.x2 = (double)x2/72.0;
791 data.rect.y2 = (double)m_height/1200.0 - (double)y2/72.0;
792
793 data.clear();
794 while (m_input->tell() <= m_recordEnd)
795 data.append((char)readU8());
796 data.mimeType = "application/x-postscript";
797 if (data.size())
798 m_painter->drawImageObject(data);
799 }
800
handlePostscriptTypeTwo()801 void WPG1Parser::handlePostscriptTypeTwo()
802 {
803 if (!m_graphicsStarted)
804 return;
805 #ifdef DEBUG
806 unsigned lengthOfData = readU32();
807 int rotation = readS16();
808 #else
809 readU32();
810 readS16();
811 #endif
812 int x1 = readS16();
813 int y1 = readS16();
814 int x2 = readS16();
815 int y2 = readS16();
816
817 WPG_DEBUG_MSG(("Postscript (Type 2)\n"));
818 WPG_DEBUG_MSG((" Length of Data: %d\n", lengthOfData));
819 WPG_DEBUG_MSG((" Rotation Angle: %d\n", rotation));
820 WPG_DEBUG_MSG((" Bottom left corner: %d,%d\n", x1, y1));
821 WPG_DEBUG_MSG((" Top right corner: %d,%d\n", x2, y2));
822
823 y1 = m_height - y1;
824 y2 = m_height - y2;
825
826 long xs1 = (x1 <= x2) ? x1 : x2;
827 long xs2 = (x1 <= x2) ? x2 : x1;
828 long ys1 = (y1 <= y2) ? y1 : y2;
829 long ys2 = (y1 <= y2) ? y2 : y1;
830 WPG_DEBUG_MSG(("%li %li %li %li\n", xs1, ys1, xs2, ys2));
831
832 libwpg::WPGBinaryData data;
833 data.rect.x1 = (double)xs1/1200.0;
834 data.rect.y1 = (double)(ys1)/1200.0;
835 data.rect.x2 = (double)xs2/1200.0;
836 data.rect.y2 = (double)(ys2)/1200.0;
837
838 data.mimeType = "image/x-eps";
839
840 m_input->seek(48, WPX_SEEK_CUR);
841
842 data.clear();
843 while (m_input->tell() <= m_recordEnd)
844 data.append((char)readU8());
845 if (data.size())
846 m_painter->drawImageObject(data);
847 }
848
resetPalette()849 void WPG1Parser::resetPalette()
850 {
851 m_colorPalette.clear();
852 for (int i=0; i<256; i++)
853 {
854 libwpg::WPGColor color;
855 color.red = defaultWPG1PaletteRed[i];
856 color.green = defaultWPG1PaletteGreen[i];
857 color.blue = defaultWPG1PaletteBlue[i];
858 m_colorPalette[i] = color;
859 }
860 }
861
862