1 /*
2 drvsvm.cpp : This file is part of pstoedit
3 Backend for OpenOffice metafile (SVM - StarView metafile)
4
5 Copyright (C) 2005 Thorsten Behrens (tbehrens at acm.org)
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22 #include "drvsvm.h"
23 #include "svm_actions.h"
24
25 #include I_string_h
26 #include I_fstream
27 #include I_stdio
28 #include I_stdlib
29
30 #include <math.h>
31 #include <utility>
32 #include <vector>
33
34 /* TODO section:
35 *
36 * Check the following example files again:
37 * - largetextspace.ps
38 * - colrtest.ps
39 * - images
40 * - bounding box
41 */
42
43 /* Most of the information necessary to read/write SVM files is
44 * available only by reading the code - for the parts used here, this
45 * is vcl/inc/metaact.hxx, vcl/inc/font.hxx, vcl/inc/vclenum.hxx and
46 * the corresponding source files in vcl/source/gdi. The actual
47 * reading/writing of SVMs resides in vcl/source/gdi/gdimtf.cxx (all
48 * files relative to the OpenOffice.org source tree, of course).
49 */
50
51 namespace {
52 // const char description[] = "generated by SVM backend of pstoedit\0input\0\0";
53
writePod(ostream & outf,const T value)54 template< typename T > void writePod(ostream& outf,
55 const T value)
56 {
57 outf.write( const_cast<char*>(
58 reinterpret_cast<const char*>(&value)),
59 sizeof(value) );
60 }
61
62 #ifdef PS_BIG_ENDIAN
63 // taken from OpenOffice.org, sal/inc/osl/endian.h (LGPLed)
64 # define MAKEWORD(bl, bh) ((drvSVM::uInt16)((bl) & 0xFF) | (((drvSVM::uInt16)(bh) & 0xFF) << 8))
65 # define LOBYTE(w) ((drvSVM::uInt8)((drvSVM::uInt16)(w) & 0xFF))
66 # define HIBYTE(w) ((drvSVM::uInt8)(((drvSVM::uInt16)(w) >> 8) & 0xFF))
67 # define MAKEDWORD(wl, wh) ((drvSVM::uInt32)((wl) & 0xFFFF) | (((drvSVM::uInt32)(wh) & 0xFFFF) << 16))
68 # define LOWORD(d) ((drvSVM::uInt16)((drvSVM::uInt32)(d) & 0xFFFF))
69 # define HIWORD(d) ((drvSVM::uInt16)(((drvSVM::uInt32)(d) >> 16) & 0xFFFF))
70 # define SWAPWORD(w) MAKEWORD(HIBYTE(w),LOBYTE(w))
71
72 // have to override >8 bit writes, since SVM is little-endian -
73 // note further that we _don't_ need to override the signed types,
74 // too - integral promotion does happen for normal method lookup
75 // (compared to choosing a template specialization)
76
writePod(ostream & outf,drvSVM::uInt16 value)77 void writePod(ostream& outf,
78 drvSVM::uInt16 value)
79 {
80 value = SWAPWORD(value);
81 outf.write( const_cast<char*>(
82 reinterpret_cast<const char*>(&value)),
83 sizeof(drvSVM::uInt16) );
84 }
85
writePod(ostream & outf,drvSVM::uInt32 value)86 void writePod(ostream& outf,
87 drvSVM::uInt32 value)
88 {
89 value = MAKEDWORD(SWAPWORD(HIWORD(value)),
90 SWAPWORD(LOWORD(value)));
91 outf.write( const_cast<char*>(
92 reinterpret_cast<const char*>(&value)),
93 sizeof(drvSVM::uInt32) );
94 }
95 #endif
96
fakeVersionCompat(ostream & outf,drvSVM::uInt16 versionId,drvSVM::uInt32 len)97 static void fakeVersionCompat(ostream& outf,
98 drvSVM::uInt16 versionId,
99 drvSVM::uInt32 len)
100 {
101 writePod(outf, versionId);
102 writePod(outf, len);
103 }
104 }
105
derivedConstructor(drvSVM)106 drvSVM::derivedConstructor(drvSVM) :
107 constructBase,
108 headerPos(0),
109 actionCount(0),
110 isDriverOk(close_output_file_and_reopen_in_binary_mode())
111 {
112 // setup driver base class
113 const char *const defaultfontname = "System";
114 setCurrentFontName(defaultfontname, false /* is standard font */ );
115
116 x_offset = 0.0;
117 y_offset = currentDeviceHeight; // need to mirror in y
118
119
120 // write SVM file header
121 // ---------------------
122
123 outf << "VCLMTF";
124 fakeVersionCompat(outf, 1, 0x31);
125
126 // stream compress mode
127 writePod(outf, (uInt32)0);
128
129 headerPos = outf.tellp();
130
131 // pref mapmode (place holder, gets written again in destructor)
132 fakeVersionCompat(outf, 1, 0x1b);
133 writePod(outf, (uInt16)0); // map unit: 100th mm
134 writePod(outf, (Int32)0); // origin x
135 writePod(outf, (Int32)0); // origin y
136 writePod(outf, (Int32)1); // scale x numerator
137 writePod(outf, (Int32)1); // scale x denominator
138 writePod(outf, (Int32)1); // scale y numerator
139 writePod(outf, (Int32)1); // scale y denominator
140 writePod(outf, (uInt8)0); // 'simple' mapmode flag
141
142 // pref size
143 writePod(outf, (Int32)0); // prefsize x
144 writePod(outf, (Int32)0); // prefsize y
145
146 // action count
147 writePod(outf, (uInt32)0);
148
149 // set PostScript-compatible text alignment
150 writePod(outf,
151 (uInt16)META_TEXTALIGN_ACTION);
152 fakeVersionCompat(outf, 1, 0);
153 writePod(outf, (uInt16)1); // alignment: baseline
154 ++actionCount;
155 }
156
~drvSVM()157 drvSVM::~drvSVM()
158 {
159 const BBox& psBBox( getCurrentBBox() );
160
161 // write out pref mapmode (can only do that now reliably, as
162 // during construction, input might not have been fully parsed)
163 outf.seekp(headerPos);
164
165 if (Verbose())
166 errf << "calculated Bounding Box: "
167 << l_transX(psBBox.ll.x_)
168 << " "
169 << l_transY(psBBox.ur.y_)
170 << " "
171 << l_transX(psBBox.ur.x_)
172 << " "
173 << l_transY(psBBox.ll.y_) << endl;
174
175 // pref mapmode
176 fakeVersionCompat(outf, 1, 0x1b);
177 writePod(outf, (uInt16)0); // map unit: 100th mm
178 writePod(outf,
179 (Int32)l_transX(psBBox.ll.x_)); // origin x
180 writePod(outf,
181 (Int32)l_transY(psBBox.ur.y_)); // origin y
182
183 // convert between pt and 100th mm (factor 35.14598)
184 writePod(outf, (Int32)3514598); // scale x numerator
185 writePod(outf, (Int32)100000); // scale x denominator
186 writePod(outf, (Int32)3514598); // scale y numerator
187 writePod(outf, (Int32)100000); // scale y denominator
188 writePod(outf, (uInt8)0); // clear 'simple' mapmode flag
189
190 // pref size
191 writePod(outf, (Int32)abs(
192 l_transX(psBBox.ll.x_) - l_transX(psBBox.ur.x_)) + 1 ); // prefsize x
193 writePod(outf, (Int32)abs(
194 l_transY(psBBox.ll.y_) - l_transY(psBBox.ur.y_)) + 1 ); // prefsize y
195
196 // action count
197 writePod(outf, (uInt32)actionCount);
198 }
199
setAttrs(LineColorAction eLineAction,FillColorAction eFillAction)200 void drvSVM::setAttrs( LineColorAction eLineAction,
201 FillColorAction eFillAction )
202 {
203 // write MetaLineColorAction
204 writePod(outf,
205 (uInt16)META_LINECOLOR_ACTION);
206 fakeVersionCompat(outf, 1, 0);
207 writePod(outf,
208 (uInt8)(edgeB()*255 + .5));
209 writePod(outf,
210 (uInt8)(edgeG()*255 + .5));
211 writePod(outf,
212 (uInt8)(edgeR()*255 + .5));
213 writePod(outf,(uInt8)0); // dummy
214
215 switch( eLineAction )
216 {
217 case lineColor:
218 // switch on line color
219 writePod(outf, (uInt8)1);
220 break;
221
222 case noLineColor:
223 // switch off line color
224 writePod(outf, (uInt8)0);
225 break;
226
227 default:
228 assert (0 && "Unknown line color action");
229 break;
230 }
231
232 ++actionCount;
233
234 // write MetaFillColorAction
235 writePod(outf,
236 (uInt16)META_FILLCOLOR_ACTION);
237 fakeVersionCompat(outf, 1, 0);
238 writePod(outf,
239 (uInt8)(fillB()*255 + .5));
240 writePod(outf,
241 (uInt8)(fillG()*255 + .5));
242 writePod(outf,
243 (uInt8)(fillR()*255 + .5));
244 writePod(outf,(uInt8)0); // dummy
245
246 switch( eFillAction )
247 {
248 case fillColor:
249 // switch on fill color
250 writePod(outf, (uInt8)1);
251 break;
252
253 case noFillColor:
254 // switch off fill color
255 writePod(outf, (uInt8)0);
256 break;
257
258 default:
259 assert (0 && "Unknown fill color action");
260 break;
261 }
262
263 ++actionCount;
264 }
265
ClipPath(cliptype)266 void drvSVM::ClipPath(cliptype /* clipmode*/)
267 {
268 }
269
Save()270 void drvSVM::Save()
271 {
272 }
273
Restore()274 void drvSVM::Restore()
275 {
276 }
277
close_page()278 void drvSVM::close_page()
279 {
280 // NOOP in drvsvm
281 }
282
283
open_page()284 void drvSVM::open_page()
285 {
286 // NOOP in drvsvm
287 }
288
write_path(VectorOfVectorOfPoints const & polyPolygon,VectorOfVectorOfFlags const & polyPolygonFlags)289 void drvSVM::write_path( VectorOfVectorOfPoints const& polyPolygon,
290 VectorOfVectorOfFlags const& polyPolygonFlags )
291 {
292 // write MetaPolyPolygonAction
293 writePod(outf,
294 (uInt16)META_POLYPOLYGON_ACTION);
295 fakeVersionCompat(outf, 2, 0);
296 const std::size_t numPolies( polyPolygon.size() );
297
298 // write polyPolygon.size() empty polygons
299 writePod(outf, (uInt16)numPolies);
300 {for( std::size_t i=0; i<numPolies; ++i )
301 writePod(outf, (uInt16)0);}
302
303 // write polyPolygon.size() polygons, possibly with curves
304 writePod(outf, (uInt16)numPolies);
305 {for( std::size_t i=0; i<numPolies; ++i )
306 {
307 // write out index (the polygons written here are 'replacing'
308 // the dummies written above, at the given index)
309 writePod(outf, (uInt16)i);
310
311 fakeVersionCompat(outf, 1, 0);
312 writePod(outf, (uInt16)polyPolygon[i].size());
313 outf.write( reinterpret_cast<char*>(
314 const_cast<IntPoint*>( &polyPolygon[i][0] )),
315 sizeof(IntPoint)*polyPolygon[i].size() );
316 writePod(outf, (uInt8)1); // flag: have flag array
317 outf.write( reinterpret_cast<char*>(
318 const_cast<uInt8*>( &polyPolygonFlags[i][0] )),
319 sizeof(uInt8)*polyPolygonFlags[i].size() );
320 }}
321
322 ++actionCount;
323 }
324
write_polyline(VectorOfVectorOfPoints const & polyPolygon,VectorOfVectorOfFlags const & polyPolygonFlags)325 void drvSVM::write_polyline( VectorOfVectorOfPoints const& polyPolygon,
326 VectorOfVectorOfFlags const& polyPolygonFlags )
327 {
328 const std::size_t numPolies( polyPolygon.size() );
329 for( std::size_t currPoly=0; currPoly<numPolies; ++currPoly ) {
330 // write MetaPolyLineAction
331 writePod(outf,
332 (uInt16)META_POLYLINE_ACTION);
333 fakeVersionCompat(outf, 3, 0);
334
335 // write empty polygon
336 writePod(outf, (uInt16)0);
337
338 // write LineInfo
339 fakeVersionCompat(outf, 1, 0); // TODO(F2): support V2 dash/dot parameterization
340 switch (currentLineType()) {
341 case dotted:
342 case dashed:
343 case dashdot:
344 case dashdotdot:
345 writePod(outf, (uInt16)2);
346 break;
347
348 case solid:
349 writePod(outf, (uInt16)1);
350 break;
351
352 default:
353 assert (0 && "Unknown line pattern type");
354 break;
355 }
356 writePod(outf, (Int32)(currentLineWidth() + .5));
357
358 // write out actual polygon data
359 writePod(outf, (uInt8)1); // flag, enabling following polygon
360
361 fakeVersionCompat(outf, 1, 0);
362 writePod(outf, (uInt16)polyPolygon[currPoly].size());
363 outf.write( reinterpret_cast<char*>(
364 const_cast<IntPoint*>( &polyPolygon[currPoly][0] )),
365 sizeof(IntPoint)*polyPolygon[currPoly].size() );
366 writePod(outf, (uInt8)1); // flag: have flag array
367 outf.write( reinterpret_cast<char*>(
368 const_cast<uInt8*>( &polyPolygonFlags[currPoly][0] )),
369 sizeof(uInt8)*polyPolygonFlags[currPoly].size() );
370
371 ++actionCount;
372 }
373 }
374
show_path()375 void drvSVM::show_path()
376 {
377 // create poly-polygon from path info
378 // ----------------------------------
379
380 VectorOfVectorOfPoints polyPolygon;
381 VectorOfPoints currPolygon;
382 VectorOfVectorOfFlags polyPolygonFlags;
383 VectorOfFlags currPolygonFlags;
384
385 const unsigned int numElems(numberOfElementsInPath());
386 for(unsigned int n=0; n<numElems; ++n) {
387 const basedrawingelement& elem( pathElement(n) );
388 switch (elem.getType()) {
389 case moveto:
390 {
391 // TODO(P3): lots of copying here...
392 if( !currPolygon.empty() )
393 {
394 polyPolygon.push_back(currPolygon);
395 polyPolygonFlags.push_back(currPolygonFlags);
396 currPolygon.clear();
397 currPolygonFlags.clear();
398 }
399 }
400
401 // FALLTHROUGH intended
402 case lineto:
403 {
404 const Point& p( elem.getPoint(0) );
405 currPolygon.push_back(
406 std::make_pair( (Int32)l_transX(p.x_),
407 (Int32)l_transY(p.y_) ));
408 currPolygonFlags.push_back(0);
409 }
410 break;
411
412 case closepath:
413 {
414 if( !currPolygon.empty() )
415 {
416 // append first point again
417 currPolygon.push_back( currPolygon.front() );
418 currPolygonFlags.push_back( currPolygonFlags.front() );
419
420 // TODO(P3): lots of copying here...
421 polyPolygon.push_back(currPolygon);
422 polyPolygonFlags.push_back(currPolygonFlags);
423 currPolygon.clear();
424 currPolygonFlags.clear();
425 }
426 }
427 break;
428
429 case curveto:
430 {
431 const Point& c1( elem.getPoint(0) );
432 currPolygon.push_back(
433 std::make_pair( (Int32)l_transX(c1.x_),
434 (Int32)l_transY(c1.y_) ));
435 currPolygonFlags.push_back(2);
436
437 const Point& c2( elem.getPoint(1) );
438 currPolygon.push_back(
439 std::make_pair( (Int32)l_transX(c2.x_),
440 (Int32)l_transY(c2.y_) ));
441 currPolygonFlags.push_back(2);
442
443 const Point& p2( elem.getPoint(2) );
444 currPolygon.push_back(
445 std::make_pair( (Int32)l_transX(p2.x_),
446 (Int32)l_transY(p2.y_) ));
447 currPolygonFlags.push_back(0);
448 }
449 break;
450
451 default:
452 assert (0 && "Unknown path element type");
453 break;
454 }
455 }
456
457 // finish last active polygon
458 if( !currPolygon.empty() )
459 {
460 // TODO(P3): lots of copying here...
461 polyPolygon.push_back(currPolygon);
462 polyPolygonFlags.push_back(currPolygonFlags);
463 currPolygon.clear();
464 currPolygonFlags.clear();
465 }
466
467
468 // determine path type: fill or line
469 // ---------------------------------
470 const bool need_line_info( currentLineType() != solid ||
471 currentLineWidth() > 0 );
472 switch (currentShowType()) {
473 case drvbase::stroke:
474 {
475 setAttrs( lineColor, noFillColor );
476
477 if (need_line_info)
478 {
479 write_polyline( polyPolygon, polyPolygonFlags );
480 }
481 else
482 {
483 write_path( polyPolygon, polyPolygonFlags );
484 }
485 }
486 break;
487
488 case drvbase::fill:
489 case drvbase::eofill:
490 {
491 if (pathWasMerged())
492 {
493 setAttrs( lineColor, fillColor );
494
495 write_path( polyPolygon, polyPolygonFlags );
496 if (need_line_info)
497 write_polyline( polyPolygon, polyPolygonFlags );
498 }
499 else
500 {
501 setAttrs( noLineColor, fillColor );
502 write_path( polyPolygon, polyPolygonFlags );
503 }
504 }
505 break;
506
507 default:
508 assert (0 && "Unknown path show type");
509 break;
510 }
511 }
512
513
show_text(const TextInfo & textinfo)514 void drvSVM::show_text(const TextInfo& textinfo)
515 {
516 if (fontchanged())
517 {
518 static const char* symbolName = "symbol";
519
520 // TODO(F2): evaluate textinfo.FontMatrix, and emulate
521 // advancements. Or: abort with error, and require user to
522 // re-run with '-pti' given (see largetextspace.ps example).
523
524 // write out MetaFontAction (selecting the new font into VCL
525 // OutputDevice)
526 const Int16 fontHeight = (short int) (textinfo.currentFontSize + .5);
527 const Int16 fontAngle = (short int) (10 * textinfo.currentFontAngle + .5);
528
529 Int16 fontWidth = 0;
530 uInt16 fontWeigth = 0; // default: don't care
531 uInt16 fontItalic = 0; // default: no italics
532 uInt16 charSet = 0; // default: don't know charset
533
534 const char* fontName = NULL;
535
536 if (strstr(textinfo.currentFontWeight.c_str(), "Regular"))
537 fontWeigth = 4; // semi light weight
538
539 if (strstr(textinfo.currentFontWeight.c_str(), "Normal"))
540 fontWeigth = 5; // normal weight
541
542 if (strstr(textinfo.currentFontWeight.c_str(), "Medium"))
543 fontWeigth = 6; // medium weight
544
545 if (options->emulateNarrowFonts) {
546 if (strstr(textinfo.currentFontWeight.c_str(), "Thin") ||
547 strstr(textinfo.currentFontName.c_str(), "Thin") ||
548 strstr(textinfo.currentFontFullName.c_str(), "Thin")) {
549 fontWidth = fontHeight / 3; // narrow font emulation (trial and error value for Arial font)
550 }
551
552 if (strstr(textinfo.currentFontWeight.c_str(), "Extralight") ||
553 strstr(textinfo.currentFontName.c_str(), "Extralight") ||
554 strstr(textinfo.currentFontFullName.c_str(), "Extralight")) {
555 fontWidth = fontHeight / 4; // narrow font emulation (trial and error value for Arial font)
556 }
557
558 if (strstr(textinfo.currentFontWeight.c_str(), "Ultralight") ||
559 strstr(textinfo.currentFontName.c_str(), "Ultralight") ||
560 strstr(textinfo.currentFontFullName.c_str(), "Ultralight")) {
561 fontWidth = fontHeight / 4; // narrow font emulation (trial and error value for Arial font)
562 }
563
564 if (strstr(textinfo.currentFontWeight.c_str(), "Light") ||
565 strstr(textinfo.currentFontName.c_str(), "Light") ||
566 strstr(textinfo.currentFontFullName.c_str(), "Light") ||
567 strstr(textinfo.currentFontWeight.c_str(), "Condensed") ||
568 strstr(textinfo.currentFontName.c_str(), "Condensed") ||
569 strstr(textinfo.currentFontFullName.c_str(), "Condensed")) {
570 fontWidth = fontHeight / 3; // narrow font emulation (trial and error value for Arial font)
571 }
572 }
573 else {
574 if (strstr(textinfo.currentFontWeight.c_str(), "Thin"))
575 fontWeigth = 1; // thin
576
577 if (strstr(textinfo.currentFontWeight.c_str(), "Extralight"))
578 fontWeigth = 1; // thin
579
580 if (strstr(textinfo.currentFontWeight.c_str(), "Ultralight"))
581 fontWeigth = 2; // ultra light
582
583 if (strstr(textinfo.currentFontWeight.c_str(), "Light") ||
584 strstr(textinfo.currentFontWeight.c_str(), "Condensed"))
585 fontWeigth = 3; // light
586 }
587
588 if (strstr(textinfo.currentFontWeight.c_str(), "Semibold") ||
589 strstr(textinfo.currentFontName.c_str(), "Semibold") ||
590 strstr(textinfo.currentFontFullName.c_str(), "Semibold"))
591 fontWeigth = 7; // semibold
592
593 if (strstr(textinfo.currentFontWeight.c_str(), "Demibold") ||
594 strstr(textinfo.currentFontName.c_str(), "Demibold") ||
595 strstr(textinfo.currentFontFullName.c_str(), "Demibold"))
596 fontWeigth = 7; // semibold
597
598 if (strstr(textinfo.currentFontWeight.c_str(), "Bold") ||
599 strstr(textinfo.currentFontName.c_str(), "Bold") ||
600 strstr(textinfo.currentFontFullName.c_str(), "Bold"))
601 fontWeigth = 8; // bold
602
603 if (strstr(textinfo.currentFontWeight.c_str(), "Extrabold") ||
604 strstr(textinfo.currentFontName.c_str(), "Extrabold") ||
605 strstr(textinfo.currentFontFullName.c_str(), "Extrabold"))
606 fontWeigth = 8; // bold
607
608 if (strstr(textinfo.currentFontWeight.c_str(), "Ultrabold") ||
609 strstr(textinfo.currentFontName.c_str(), "Ultrabold") ||
610 strstr(textinfo.currentFontFullName.c_str(), "Ultrabold"))
611 fontWeigth = 9; // ultrabold
612
613 if (strstr(textinfo.currentFontWeight.c_str(), "Heavy") ||
614 strstr(textinfo.currentFontName.c_str(), "Heavy") ||
615 strstr(textinfo.currentFontFullName.c_str(), "Heavy"))
616 fontWeigth = 9; // ultrabold
617
618 if (strstr(textinfo.currentFontWeight.c_str(), "Black") ||
619 strstr(textinfo.currentFontName.c_str(), "Black") ||
620 strstr(textinfo.currentFontFullName.c_str(), "Black"))
621 fontWeigth = 10; // black
622
623 if ((strstr(textinfo.currentFontName.c_str(), "Italic") != NIL) ||
624 (strstr(textinfo.currentFontFullName.c_str(), "Italic") != NIL))
625 fontItalic = 2; // normal italics
626
627 if ((strstr(textinfo.currentFontName.c_str(), "Oblique") != NIL) ||
628 (strstr(textinfo.currentFontFullName.c_str(), "Oblique") != NIL))
629 fontItalic = 1; // oblique italics
630
631 if ((strstr(textinfo.currentFontFullName.c_str(), "Symbol") != NIL) ||
632 (strstr(textinfo.currentFontFullName.c_str(), "symbol") != NIL)) {
633 charSet = 10; // symbol charset
634 fontName = symbolName;
635 } else {
636 charSet = 11; // ASCII-US charset
637 fontName = textinfo.currentFontName.c_str();
638 }
639
640 // write MetaFontAction
641 writePod(outf,
642 (uInt16)META_FONT_ACTION);
643 fakeVersionCompat(outf, 1, 0);
644
645 // serialize Font
646 fakeVersionCompat(outf, 2, 0);
647
648 // font name
649 const size_t stringLen = strlen(fontName);
650 writePod(outf,
651 (uInt16)stringLen);
652 outf.write(fontName,stringLen);
653
654 // font style
655 writePod(outf,
656 (uInt16)0);
657
658 // font size
659 writePod(outf,
660 (Int32)fontWidth);
661 writePod(outf,
662 (Int32)(-fontHeight));
663
664 // charset
665 writePod(outf,
666 (uInt16)charSet);
667
668 // TODO(F3): font family
669 writePod(outf,
670 (uInt16)0);
671
672 // font pitch
673 writePod(outf,
674 (uInt16)0);
675
676 // font weight
677 writePod(outf,
678 (uInt16)fontWeigth);
679
680 // font underline
681 writePod(outf,
682 (uInt16)0);
683
684 // font strikeout
685 writePod(outf,
686 (uInt16)0);
687
688 // font italic
689 writePod(outf,
690 (uInt16)fontItalic);
691
692 // text language
693 writePod(outf,
694 (uInt16)0);
695
696 // width type
697 writePod(outf,
698 (uInt16)0);
699
700 // font orientation
701 writePod(outf,
702 (uInt16)fontAngle);
703
704 // word line
705 writePod(outf,
706 (uInt8)0);
707
708 // TODO(F3): detect outline mode
709 writePod(outf,
710 (uInt8)0);
711
712 // shadow
713 writePod(outf,
714 (uInt8)0);
715
716 // kerning
717 writePod(outf,
718 (uInt8)0);
719
720 // relief mode
721 writePod(outf,
722 (uInt8)0);
723
724 // CJK language
725 writePod(outf,
726 (uInt16)0);
727
728 // vertical writing mode
729 writePod(outf,
730 (uInt8)0);
731
732 // emphasis marks (esp. for CJK languages)
733 writePod(outf,
734 (uInt16)0);
735
736 ++actionCount;
737 }
738
739 // write MetaTextColorAction
740 writePod(outf,
741 (uInt16)META_TEXTCOLOR_ACTION);
742 fakeVersionCompat(outf, 1, 0);
743 writePod(outf,
744 (uInt8)(textinfo.currentB*255 + .5));
745 writePod(outf,
746 (uInt8)(textinfo.currentG*255 + .5));
747 writePod(outf,
748 (uInt8)(textinfo.currentR*255 + .5));
749 writePod(outf,(uInt8)0); // dummy
750
751 ++actionCount;
752
753 // write text
754 if( textinfo.thetext.c_str() )
755 {
756 writePod(outf,
757 (uInt16)META_TEXT_ACTION);
758 fakeVersionCompat(outf, 1, 0);
759 writePod(outf,
760 (uInt32)l_transX(textinfo.x));
761 writePod(outf,
762 (uInt32)l_transY(textinfo.y));
763
764 const size_t textLen = strlen(textinfo.thetext.c_str());
765 writePod(outf,
766 (uInt16)textLen);
767 outf.write(textinfo.thetext.c_str(),
768 textLen);
769 writePod(outf,
770 (uInt16)0);
771 writePod(outf,
772 (uInt16)textLen);
773
774 // TODO(F1): SVM is Unicode-capable, yank version compat above
775 // to 2 and write out UTF-16 string here
776
777 ++actionCount;
778 }
779 }
780
781
show_image(const PSImage & image)782 void drvSVM::show_image(const PSImage& image)
783 {
784 // first retrieve bounding box
785 Point lowerLeft, upperRight;
786 image.getBoundingBox(lowerLeft, upperRight);
787
788 const Int32 width = abs(l_transX(upperRight.x_) -
789 l_transX(lowerLeft.x_));
790 const Int32 height = abs(l_transY(upperRight.y_) -
791 l_transY(lowerLeft.y_));
792
793 // calc long-padded size of scanline
794 const long int scanlineLen = ((width * 3) + 3) & ~3L;
795 const long int maskScanlineLen = ((((width + 7) & ~7L) >> 3L) + 3) & ~3L;
796
797 // now lets get some mem
798 unsigned char* const output = new unsigned char[scanlineLen * height];
799 output[0] = 0; // init for coverity
800 unsigned char* const outputMask = new unsigned char[maskScanlineLen * height];
801 outputMask[0] = 0; // init for coverity
802
803 // setup inverse transformation matrix
804 const float matrixScale(image.normalizedImageCurrentMatrix[0] *
805 image.normalizedImageCurrentMatrix[3] -
806 image.normalizedImageCurrentMatrix[2] *
807 image.normalizedImageCurrentMatrix[1]);
808 const float inverseMatrix[] = {
809 image.normalizedImageCurrentMatrix[3] / matrixScale,
810 -image.normalizedImageCurrentMatrix[1] / matrixScale,
811 -image.normalizedImageCurrentMatrix[2] / matrixScale,
812 image.normalizedImageCurrentMatrix[0] / matrixScale,
813 (image.normalizedImageCurrentMatrix[2] *
814 image.normalizedImageCurrentMatrix[5] -
815 image.normalizedImageCurrentMatrix[4] *
816 image.normalizedImageCurrentMatrix[3]) / matrixScale,
817 (image.normalizedImageCurrentMatrix[4] *
818 image.normalizedImageCurrentMatrix[1] -
819 image.normalizedImageCurrentMatrix[0] *
820 image.normalizedImageCurrentMatrix[5]) / matrixScale
821 };
822
823 if (Verbose())
824 errf << "Image matrix: "
825 << "0: " << image.normalizedImageCurrentMatrix[0] << " "
826 << "1: " << image.normalizedImageCurrentMatrix[1] << " "
827 << "2: " << image.normalizedImageCurrentMatrix[2] << " "
828 << "3: " << image.normalizedImageCurrentMatrix[3] << " "
829 << "4: " << image.normalizedImageCurrentMatrix[4] << " "
830 << "5: " << image.normalizedImageCurrentMatrix[5] << " "
831 << endl;
832
833 // TODO(F2): interpolate
834 // TODO(P3): avoid transformation _at all_ if scale and transform suffices
835 // TODO(P3): avoid mask for the obvious cases
836
837 // now transform image
838 for (long int y=0; y < height; y++) {
839 unsigned char* currOutput = &output[scanlineLen * y];
840 unsigned char* currMaskOutput = &outputMask[maskScanlineLen * y] - 1;
841
842 for (long int x=0; x < width; x++) {
843 // now transform from device coordinate space to image space
844 const Point& currPoint( Point(x + lowerLeft.x_,
845 y + lowerLeft.y_).transform(inverseMatrix) );
846
847 // round to integers
848 const long int sourceX = (long int) (currPoint.x_ + .5);
849 const long int sourceY = (long int) (currPoint.y_ + .5);
850
851 // is the pixel within source bitmap bounds?
852 if (sourceX >= 0L && (unsigned long) sourceX < image.width &&
853 sourceY >= 0L && (unsigned long) sourceY < image.height) {
854 // okay, fetch source pixel value into
855 // RGB triplet
856
857 unsigned char r(255), g(255), b(255);
858
859 // how many components?
860 switch (image.ncomp) {
861 case 1:
862 r = g = b = image.getComponent(sourceX, sourceY, 0);
863 break;
864
865 case 3:
866 r = image.getComponent(sourceX, sourceY, 0);
867 g = image.getComponent(sourceX, sourceY, 1);
868 b = image.getComponent(sourceX, sourceY, 2);
869 break;
870
871 case 4: {
872 unsigned char C = image.getComponent(sourceX, sourceY, 0);
873 unsigned char M = image.getComponent(sourceX, sourceY, 1);
874 unsigned char Y = image.getComponent(sourceX, sourceY, 2);
875 unsigned char K = image.getComponent(sourceX, sourceY, 3);
876
877 // account for key
878 C += K;
879 M += K;
880 Y += K;
881
882 // convert color
883 r = 255 - C;
884 g = 255 - M;
885 b = 255 - Y;
886 }
887 break;
888
889 default:
890 assert (0 && "Unexpected bitmap format");
891 break;
892 }
893
894 // set color triple
895 *currOutput++ = b;
896 *currOutput++ = g;
897 *currOutput++ = r;
898
899 if( (x & 7L) == 0 )
900 ++currMaskOutput;
901
902 // set mask to opaque
903 *currMaskOutput &= ~(1L << (7L - (x & 7L)));
904 }
905 else
906 {
907 // pixel outside source bitmap bounds - set to
908 // white/transparent
909 *currOutput++ = 255;
910 *currOutput++ = 255;
911 *currOutput++ = 255;
912
913 if( (x & 7L) == 0 )
914 ++currMaskOutput;
915
916 // set mask to transparent
917 *currMaskOutput |= 1L << (7L - (x & 7L));
918 }
919 }
920 }
921
922 // write BitmapEx action
923 writePod(outf,
924 (uInt16)META_BMPEXSCALE_ACTION);
925 fakeVersionCompat(outf, 1, 0);
926
927 // write bitmap
928 // ------------
929
930 // file header
931 writePod(outf,
932 (uInt16)0x4D42);
933 writePod(outf,
934 (uInt32)(14 + 40 + scanlineLen*height));
935 writePod(outf,
936 (uInt16)0);
937 writePod(outf,
938 (uInt16)0);
939 writePod(outf,
940 (uInt32)14 + 40);
941
942 // info header
943 writePod(outf,
944 (uInt32)40);
945 writePod(outf,
946 (uInt32)width);
947 writePod(outf,
948 (uInt32)height);
949 writePod(outf,
950 (uInt16)1);
951 writePod(outf,
952 (uInt16)24);
953 writePod(outf,
954 (uInt32)0);
955 writePod(outf,
956 (uInt32)0);
957 writePod(outf,
958 (uInt32)0);
959 writePod(outf,
960 (uInt32)0);
961 writePod(outf,
962 (uInt32)0);
963 writePod(outf,
964 (uInt32)0);
965
966 // actual bitmap data
967 outf.write( (char*)output,
968 scanlineLen*height );
969
970 // magics
971 writePod(outf,
972 (uInt32)0x25091962);
973 writePod(outf,
974 (uInt32)0xACB20201);
975 writePod(outf,
976 (uInt8)2); // bitmap with mask flag
977
978
979 // write mask bitmap
980 // -----------------
981
982 // file header
983 writePod(outf,
984 (uInt16)0x4D42);
985 writePod(outf,
986 (uInt32)(14 + 40 + 8 + maskScanlineLen*height));
987 writePod(outf,
988 (uInt16)0);
989 writePod(outf,
990 (uInt16)0);
991 writePod(outf,
992 (uInt32)14 + 40 + 8);
993
994 // info header
995 writePod(outf,
996 (uInt32)40);
997 writePod(outf,
998 (uInt32)width);
999 writePod(outf,
1000 (uInt32)height);
1001 writePod(outf,
1002 (uInt16)1);
1003 writePod(outf,
1004 (uInt16)1);
1005 writePod(outf,
1006 (uInt32)0);
1007 writePod(outf,
1008 (uInt32)0);
1009 writePod(outf,
1010 (uInt32)0);
1011 writePod(outf,
1012 (uInt32)0);
1013 writePod(outf,
1014 (uInt32)2);
1015 writePod(outf,
1016 (uInt32)2);
1017
1018 // bitmap palette: black and white
1019 writePod(outf,
1020 (uInt32)0);
1021 writePod(outf,
1022 (uInt32)0x00FFFFFF);
1023
1024 // actual bitmap data
1025 outf.write( (char*)outputMask,
1026 maskScanlineLen*height );
1027
1028 // output position
1029 writePod(outf,
1030 (Int32)l_transX(lowerLeft.x_));
1031 writePod(outf,
1032 (Int32)l_transY(upperRight.y_));
1033
1034 // output scale
1035 writePod(outf,
1036 (Int32)width);
1037 writePod(outf,
1038 (Int32)height);
1039
1040 ++actionCount;
1041
1042 delete[] output;
1043 delete[] outputMask;
1044 }
1045
1046
1047 static DriverDescriptionT < drvSVM > D_svm("svm",
1048 "StarView/OpenOffice.org metafile",
1049 "StarView/OpenOffice.org metafile, readable from OpenOffice.org 1.0/StarOffice 6.0 and above.",
1050 "svm",
1051 true, // backend supports subpathes
1052 true, // backend does support curves
1053 true, // backend supports elements which are filled and have edges
1054 true, // backend supports text
1055 DriverDescription::memoryeps, // no support for PNG file images
1056 DriverDescription::normalopen, // we open output file ourselves
1057 false, // if format supports multiple pages in one file (DEFINETELY not)
1058 true // clipping
1059 );
1060
1061