]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcsvg.cpp
don't write the strings to the stream one char at a time, it's *horribly* slow
[wxWidgets.git] / src / common / dcsvg.cpp
CommitLineData
cdf3a589
CE
1/////////////////////////////////////////////////////////////////////////////
2// Name: svg.cpp
3// Purpose: SVG sample
4// Author: Chris Elliott
5// Modified by:
6// RCS-ID: $Id$
7// Licence: wxWindows license
8/////////////////////////////////////////////////////////////////////////////
9
10
11// For compilers that support precompilation, includes "wx/wx.h".
12#include "wx/wxprec.h"
13
14#ifdef __BORLANDC__
15#pragma hdrstop
16#endif
17
18#ifndef WX_PRECOMP
19#include "wx/wx.h"
20#endif
21
22#include "wx/svg/dcsvg.h"
23
24#include <math.h>
25#include "wx/image.h"
26
27#define wxSVG_DEBUG FALSE
28// or TRUE to see the calls being executed
29#define newline wxString(wxT("\n"))
30#define space wxString(wxT(" "))
31#define semicolon wxString(wxT(";"))
32#define wx_round(a) (int)((a)+.5)
33
34#ifdef __BORLANDC__
35#pragma warn -rch
36#pragma warn -ccc
37#endif
38
39static inline double DegToRad(double deg) { return (deg * 3.14) / 180.0; } ;
40
41wxString wxColStr ( wxColour c )
42{
43 unsigned char r, g, b ;
44 r = c.Red ();
45 g = c.Green ();
46 b = c. Blue ();
47
48 // possible Unicode bug here
49 wxString s = wxDecToHex(r) + wxDecToHex(g) + wxDecToHex(b) ;
50 return s ;
51}
52
53
54wxString wxBrushString ( wxColour c, int style )
55{
56 wxString s = wxT("fill:#") + wxColStr (c) + semicolon + space ;
57 switch ( style )
58 {
59 case wxSOLID :
60 s = s + wxT("fill-opacity:1.0; ");
61 break ;
62 case wxTRANSPARENT:
63 s = s + wxT("fill-opacity:0.0; ");
64 break ;
65
66 default :
67 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::Requested Brush Style not available")) ;
68
69 }
70 s = s + newline ;
71 return s ;
72}
73
74
75void wxSVGFileDC::Init (wxString f, int Width, int Height, float dpi)
76
77{
78 //set up things first wxDCBase does all this?
79 m_width = Width ;
80 m_height = Height ;
81
82 m_clipping = FALSE;
83 m_OK = TRUE;
84
85 m_mm_to_pix_x = dpi/25.4;
86 m_mm_to_pix_y = dpi/25.4;
87
88 m_signX = m_signY = 1;
89
90 m_userScaleX = m_userScaleY =
91 m_deviceOriginX = m_deviceOriginY = 0;
92
93 m_OriginX = m_OriginY = 0;
94 m_logicalOriginX = m_logicalOriginY = 0;
95 m_logicalScaleX = m_logicalScaleY = 0 ;
96 m_scaleX = m_scaleY = 1.0 ;
97
98 m_logicalFunction = wxCOPY;
99 m_backgroundMode = wxTRANSPARENT;
100 m_mappingMode = wxMM_TEXT;
101
102 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
103 m_textForegroundColour = *wxBLACK;
104 m_textBackgroundColour = *wxWHITE;
105 m_colour = wxColourDisplay();
106
107 m_pen = *wxBLACK_PEN;
108 m_font = *wxNORMAL_FONT;
109 m_brush = *wxWHITE_BRUSH;
110
111 m_graphics_changed = TRUE ;
112
113 ////////////////////code here
114
115 m_outfile = new wxFileOutputStream(f) ;
116 m_OK = m_outfile->Ok ();
117 if (m_OK)
118 {
119 m_filename = f ;
120 m_sub_images = 0 ;
121 wxString s ;
122 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") ; s = s + newline ;
123 m_outfile->Write (s.c_str(), s.Len() ) ;
124 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + newline ;
125 m_outfile->Write (s.c_str(), s.Len() ) ;
126 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ")+ newline ;
127 m_outfile->Write (s.c_str(), s.Len() ) ;
128 s.Printf ( wxT("<svg width=\"%.2gcm\" height=\"%.2gcm\" viewBox=\"0 0 %d %d \"> \n"), float(Width)/dpi*2.54, float(Height)/dpi*2.54, Width, Height );
129 m_outfile->Write (s.c_str(), s.Len() ) ;
130 s = wxT("<title>SVG Picture created as ") + wxFileNameFromPath(f) + wxT(" </title>") + newline ;
131 m_outfile->Write (s.c_str(), s.Len() ) ;
132 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ newline ;
133 m_outfile->Write (s.c_str(), s.Len() ) ;
134 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + newline ;
135 m_outfile->Write (s.c_str(), s.Len() ) ;
136
137 }
138 m_OK = m_outfile->Ok ();
139}
140
141
142// constructors
143wxSVGFileDC::wxSVGFileDC (wxString f)
144{
145 // quarter 640x480 screen display at 72 dpi
146 Init (f,320,240,72.0);
147};
148
149wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height)
150{
151 Init (f,Width,Height,72.0);
152};
153
154wxSVGFileDC::wxSVGFileDC (wxString f, int Width, int Height, float dpi)
155{
156 Init (f,Width,Height,dpi);
157};
158
159wxSVGFileDC::~wxSVGFileDC()
160{
161 wxString s = wxT("</g> \n</svg> \n") ;
162 m_outfile->Write (s.c_str(), s.Len() ) ;
163 m_OK = m_outfile->Ok ();
164 delete m_outfile ;
165}
166
167
168//////////////////////////////////////////////////////////////////////////////////////////
169
170void wxSVGFileDC::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
171{
172 if (m_graphics_changed) NewGraphics ();
173 wxString s ;
174 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
175 if (m_OK)
176 {
177 m_outfile->Write (s.c_str(), s.Len() ) ;
178 }
179 m_OK = m_outfile->Ok ();
180 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawLine Call executed")) ;
181 CalcBoundingBox(x1, y1) ;
182 CalcBoundingBox(x2, y2) ;
183 return;
184};
185
186void wxSVGFileDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
187{
188 for ( int i = 1; i < n ; i++ )
189 {
190 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
191 points [ i ].x + xoffset, points [ i ].y + yoffset ) ;
192 }
193}
194
195
196void wxSVGFileDC::DoDrawPoint (wxCoord x1, wxCoord y1)
197{
198 wxString s;
199 if (m_graphics_changed) NewGraphics ();
200 s = wxT("<g style = \"stroke-linecap:round;\" > ") + newline ;
201 m_outfile->Write (s.c_str(), s.Len() ) ;
202 DrawLine ( x1,y1,x1,y1 );
203 s = wxT("</g>");
204 m_outfile->Write (s.c_str(), s.Len() ) ;
205 m_OK = m_outfile->Ok ();
206}
207
208
209void wxSVGFileDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
210{
211 wxDCBase::DoDrawCheckMark (x1,y1,width,height) ;
212}
213
214
215void wxSVGFileDC::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
216{
217 DoDrawRotatedText(text, x1,y1,0.0);
218 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawText Call executed")) ;
219}
220
221
222void wxSVGFileDC::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
223{
224 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
225 if (m_graphics_changed) NewGraphics ();
226 wxString s, sTmp;
227
228 // calculate bounding box
229 wxCoord w, h, desc ;
230 DoGetTextExtent(sText, &w, &h, &desc);
231
232 double rad = DegToRad(angle);
233
234 // wxT("upper left") and wxT("upper right")
235 CalcBoundingBox(x, y);
236 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
237
238 // wxT("bottom left") and wxT("bottom right")
239 x += (wxCoord)(h*sin(rad));
240 y += (wxCoord)(h*cos(rad));
241 CalcBoundingBox(x, y);
242 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
243
244 if (m_backgroundMode == wxSOLID)
245 {
246 // draw background first
247 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
248
249 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background")) ;
250 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x,y+desc-h, w, h );
251 s = sTmp + wxT("style=\"fill:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
252 s = s + wxT("stroke-width:1; stroke:#") + wxColStr (m_textBackgroundColour) + wxT("; ") ;
253 sTmp.Printf ( wxT("\" transform=\"rotate( %.2g %d %d ) \">"), -angle, x,y ) ;
254 s = s + sTmp + newline ;
255 m_outfile->Write (s.c_str(), s.Len() ) ;
256 }
257 //now do the text itself
258 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
259
260 sTmp = m_font.GetFaceName () ;
261 if (sTmp.Len () > 0) s = s + wxT("style=\"font-family:") + sTmp + wxT("; ");
262 else s = s + wxT("style=\" ") ;
263
264 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
265 s = s + wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + semicolon + space;
266
267 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
268 s = s + wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + semicolon + space;
269
270 sTmp.Printf (wxT("font-size:%dpt; fill:#"), m_font.GetPointSize () );
271 s = s + sTmp ;
272 s = s + wxColStr (m_textForegroundColour) + wxT("; stroke:#") + wxColStr (m_textForegroundColour) + wxT("; ") ;
273 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %.2g %d %d ) \" >"), -angle, x,y ) ;
274 s = s + sTmp + sText + wxT("</text> ") + newline ;
275 if (m_OK)
276 {
277 m_outfile->Write (s.c_str(), s.Len() ) ;
278 }
279 m_OK = m_outfile->Ok ();
280 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DrawRotatedText Call executed")) ;
281
282}
283
284
285void wxSVGFileDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
286{
287 DoDrawRoundedRectangle(x, y, width, height, 0) ;
288}
289
290
291void wxSVGFileDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
292
293{
294 if (m_graphics_changed) NewGraphics ();
295 wxString s ;
296
297 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%.2g\" "),
298 x, y, width, height, radius );
299
300 s = s + wxT(" /> ") + newline ;
301 m_outfile->Write (s.c_str(), s.Len() ) ;
302 m_OK = m_outfile->Ok ();
303
304 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed")) ;
305 CalcBoundingBox(x, y) ;
306 CalcBoundingBox(x + width, y + height) ;
307
308}
309
310
311void wxSVGFileDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset,int fillStyle)
312{
313 if (m_graphics_changed) NewGraphics ();
314 wxString s, sTmp ;
315 s = wxT("<polygon style=\"") ;
316 if ( fillStyle == wxODDEVEN_RULE )
317 s = s + wxT("fill-rule:evenodd; ");
318 else
319 s = s + wxT("fill-rule:nonzero; ");
320
321 s = s + wxT("\" \npoints=\"") ;
322
323 for (int i = 0; i < n; i++)
324 {
325 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
326 s = s + sTmp + newline ;
327 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
328 }
329 s = s + wxT("\" /> ") ;
330 s = s + newline ;
331 m_outfile->Write (s.c_str(), s.Len() ) ;
332 m_OK = m_outfile->Ok ();
333
334 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawPolygon Call executed")) ;
335}
336
337
338void wxSVGFileDC::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
339
340{
341 if (m_graphics_changed) NewGraphics ();
342
343 int rh = height /2 ;
344 int rw = width /2 ;
345
346 wxString s;
347 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
348 s = s + wxT(" /> ") + newline ;
349
350 m_outfile->Write (s.c_str(), s.Len() ) ;
351 m_OK = m_outfile->Ok ();
352
353 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipse Call executed")) ;
354 CalcBoundingBox(x, y) ;
355 CalcBoundingBox(x + width, y + height) ;
356}
357
358
359void wxSVGFileDC::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
360{
361 /* Draws an arc of a circle, centred on (xc, yc), with starting point
362 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
363 and the current brush for filling the shape.
364
365 The arc is drawn in an anticlockwise direction from the start point to
366 the end point.
367
368 Might be better described as Pie drawing */
369
370 if (m_graphics_changed) NewGraphics ();
371 wxString s ;
372
373 // we need the radius of the circle which has two estimates
374 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
375 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
376
377 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle")) ;
378 if ( fabs ( r2-r1 ) > 3 ) //pixels
379 {
380 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n") ;
381 m_outfile->Write (s.c_str(), s.Len() ) ;
382 }
383
384 double theta1 = atan2(yc-y1,x1-xc);
385 if ( theta1 < 0 ) theta1 = theta1 + 3.14 * 2;
386 double theta2 = atan2(yc-y2, x2-xc);
387 if ( theta2 < 0 ) theta2 = theta2 + 3.14 * 2;
388 if ( theta2 < theta1 ) theta2 = theta2 + 3.14 *2 ;
389
390 int fArc ; // flag for large or small arc 0 means less than 180 degrees
391 if ( fabs((theta2 - theta1) > 3.14 )) fArc = 1; else fArc = 0 ;
392
393 int fSweep = 0 ; // flag for sweep always 0
394
395 s.Printf ( wxT("<path d=\"M%d %d A%.2g %.2g 0.0 %d %d %d %d L%d %d z "),
396 x1,y1, r1, r2, fArc, fSweep, x2, y2, xc, yc );
397
398 // the z means close the path and fill
399 s = s + wxT(" \" /> ") + newline ;
400
401
402 if (m_OK)
403 {
404 m_outfile->Write (s.c_str(), s.Len() ) ;
405 }
406 m_OK = m_outfile->Ok ();
407
408 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawArc Call executed")) ;
409}
410
411
412void wxSVGFileDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
413{
414 /*
415 Draws an arc of an ellipse. The current pen is used for drawing the arc
416 and the current brush is used for drawing the pie. This function is
417 currently only available for X window and PostScript device contexts.
418
419 x and y specify the x and y coordinates of the upper-left corner of the
420 rectangle that contains the ellipse.
421
422 width and height specify the width and height of the rectangle that
423 contains the ellipse.
424
425 start and end specify the start and end of the arc relative to the
426 three-o'clock position from the center of the rectangle. Angles are
427 specified in degrees (360 is a complete circle). Positive values mean
428 counter-clockwise motion. If start is equal to end, a complete ellipse
429 will be drawn. */
430
431 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
432
433 if (m_graphics_changed) NewGraphics ();
434
435 wxString s ;
436 //radius
437 double rx = w / 2 ;
438 double ry = h / 2 ;
439 // center
440 double xc = x + rx ;
441 double yc = y + ry ;
442
443 double xs, ys, xe, ye ;
444 xs = xc + rx * cos (DegToRad(sa)) ;
445 xe = xc + rx * cos (DegToRad(ea)) ;
446 ys = yc - ry * sin (DegToRad(sa)) ;
447 ye = yc - ry * sin (DegToRad(ea)) ;
448
449 ///now same as circle arc...
450
451 double theta1 = atan2(ys-yc, xs-xc);
452 double theta2 = atan2(ye-yc, xe-xc);
453
454 int fArc ; // flag for large or small arc 0 means less than 180 degrees
455 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0 ;
456
457 int fSweep ;
458 if ( fabs( (theta2 - theta1) > 3.14)) fSweep = 1; else fSweep = 0 ;
459
460 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
461 int(xs), int(ys), int(rx), int(ry),
462 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
463
464
465 s = s + wxT(" \" /> ") + newline ;
466
467 if (m_OK)
468 {
469 m_outfile->Write (s.c_str(), s.Len() ) ;
470 }
471 m_OK = m_outfile->Ok ();
472
473 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed")) ;
474}
475
476
477void wxSVGFileDC::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , wxFont *font) const
478
479{
480 wxScreenDC sDC ;
481
482 sDC.SetFont (m_font);
483 if ( font != NULL ) sDC.SetFont ( *font );
484 sDC.GetTextExtent(string, w, h, descent, externalLeading );
485 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetTextExtent Call executed")) ;
486}
487
488
489wxCoord wxSVGFileDC::GetCharHeight() const
490
491{
492 wxScreenDC sDC ;
493 sDC.SetFont (m_font);
494
495 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharHeight Call executing")) ;
496 return ( sDC.GetCharHeight() );
497
498}
499
500
501wxCoord wxSVGFileDC::GetCharWidth() const
502{
503 wxScreenDC sDC ;
504 sDC.SetFont (m_font);
505
506 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::GetCharWidth Call executing")) ;
507 return ( sDC.GetCharWidth() ) ;
508
509}
510
511
512/// Set Functions /////////////////////////////////////////////////////////////////
513void wxSVGFileDC::SetBackground( const wxBrush &brush )
514{
515
516 m_backgroundBrush = brush;
517 return;
518}
519
520
521void wxSVGFileDC::SetBackgroundMode( int mode )
522{
523 m_backgroundMode = mode;
524 return;
525}
526
527
528void wxSVGFileDC::SetBrush(const wxBrush& brush)
529
530{
531 m_brush = brush ;
532
533 m_graphics_changed = TRUE ;
534 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetBrush Call executed")) ;
535}
536
537
538void wxSVGFileDC::SetPen(const wxPen& pen)
539{
540 // width, color, ends, joins : currently implemented
541 // dashes, stipple : not implemented
542 m_pen = pen ;
543
544 m_graphics_changed = TRUE ;
545 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetPen Call executed")) ;
546}
547
548void wxSVGFileDC::NewGraphics ()
549{
550
551 int w = m_pen.GetWidth ();
552 wxColour c = m_pen.GetColour () ;
553
554 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
555
556 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour (), m_brush.GetStyle () )
557 + wxT(" stroke:#") + wxColStr (c) + wxT("; ") ;
558
559 switch ( m_pen.GetCap () )
560 {
561 case wxCAP_PROJECTING :
562 sPenCap = wxT("stroke-linecap:square; ") ;
563 break ;
564 case wxCAP_BUTT :
565 sPenCap = wxT("stroke-linecap:butt; ") ;
566 break ;
567 case wxCAP_ROUND :
568 default :
569 sPenCap = wxT("stroke-linecap:round; ") ;
570 };
571 switch ( m_pen.GetJoin () )
572 {
573 case wxJOIN_BEVEL :
574 sPenJoin = wxT("stroke-linejoin:bevel; ") ;
575 break ;
576 case wxJOIN_MITER :
577 sPenJoin = wxT("stroke-linejoin:miter; ") ;
578 break ;
579 case wxJOIN_ROUND :
580 default :
581 sPenJoin = wxT("stroke-linejoin:round; ") ;
582 };
583
584 switch ( m_pen.GetStyle () )
585 {
586 case wxSOLID :
587 sPenStyle = wxT("stroke-opacity:1.0; stroke-opacity:1.0; ") ;
588 break ;
589 case wxTRANSPARENT :
590 sPenStyle = wxT("stroke-opacity:0.0; stroke-opacity:0.0; ") ;
591 break ;
592 default :
593 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::SetPen Call called to set a Style which is not available")) ;
594 sWarn = sWarn + wxT("<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n") ;
595 }
596
597 sLast.Printf ( wxT("stroke-width:%d\" \n transform=\"translate(%.2g %.2g) scale(%.2g %.2g)\">"),
598 w, m_OriginX, m_OriginY, m_scaleX, m_scaleY );
599
600 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + newline + sWarn;
601 m_outfile->Write (s.c_str(), s.Len() ) ;
602 m_OK = m_outfile->Ok ();
603 m_graphics_changed = FALSE ;
604 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::NewGraphics Call executed")) ;
605}
606
607
608void wxSVGFileDC::SetFont(const wxFont& font)
609
610{
611 m_font = font ;
612
613 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::SetFont Call executed")) ;
614}
615
616
617void wxSVGFileDC::ComputeScaleAndOrigin()
618{
619 m_scaleX = m_logicalScaleX * m_userScaleX;
620 m_scaleY = m_logicalScaleY * m_userScaleY;
621 m_OriginX = m_logicalOriginX * m_logicalScaleX + m_deviceOriginX ;
622 m_OriginY = m_logicalOriginY * m_logicalScaleY + m_deviceOriginY ;
623 m_graphics_changed = TRUE;
624}
625
626
627int wxSVGFileDC::GetMapMode()
628{
629 return m_mappingMode ;
630}
631
632
633void wxSVGFileDC::SetMapMode( int mode )
634{
635 switch (mode)
636 {
637 case wxMM_TWIPS:
638 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
639 break;
640 case wxMM_POINTS:
641 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
642 break;
643 case wxMM_METRIC:
644 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
645 break;
646 case wxMM_LOMETRIC:
647 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
648 break;
649 default:
650 case wxMM_TEXT:
651 SetLogicalScale( 1.0, 1.0 );
652 break;
653 }
654 m_mappingMode = mode;
655
656 /* we don't do this mega optimisation
657 if (mode != wxMM_TEXT)
658 {
659 m_needComputeScaleX = TRUE;
660 m_needComputeScaleY = TRUE;
661 }
662 */
663}
664
665
666void wxSVGFileDC::GetUserScale(double *x, double *y) const
667{
668 *x = m_userScaleX ;
669 *y = m_userScaleY ;
670}
671
672
673void wxSVGFileDC::SetUserScale( double x, double y )
674{
675 // allow negative ? -> no
676 m_userScaleX = x;
677 m_userScaleY = y;
678 ComputeScaleAndOrigin();
679}
680
681
682void wxSVGFileDC::SetLogicalScale( double x, double y )
683{
684 // allow negative ?
685 m_logicalScaleX = x;
686 m_logicalScaleY = y;
687 ComputeScaleAndOrigin();
688}
689
690
691void wxSVGFileDC::SetLogicalOrigin( wxCoord x, wxCoord y )
692{
693 // is this still correct ?
694 m_logicalOriginX = x * m_signX;
695 m_logicalOriginY = y * m_signY;
696 ComputeScaleAndOrigin();
697}
698
699
700void wxSVGFileDC::SetDeviceOrigin( wxCoord x, wxCoord y )
701{
702 // only wxPostScripDC has m_signX = -1,
703 m_deviceOriginX = x;
704 m_deviceOriginY = y;
705 ComputeScaleAndOrigin();
706}
707
708
709void wxSVGFileDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
710{
711 // only wxPostScripDC has m_signX = -1,
712 m_signX = (xLeftRight ? 1 : -1);
713 m_signY = (yBottomUp ? -1 : 1);
714 ComputeScaleAndOrigin();
715}
716
717
718// export a bitmap as a raster image in png
719bool wxSVGFileDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
720 wxDC* source, wxCoord xsrc, wxCoord ysrc,
721 int logicalFunc /*= wxCOPY*/, bool useMask /*= FALSE*/,
722 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
723{
724
725 if (logicalFunc != wxCOPY)
726 {
727 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible")) ;
728 return FALSE ;
729 }
730 if (useMask != FALSE)
731 {
732 wxASSERT_MSG(FALSE, wxT("wxSVGFileDC::DoBlit Call requested False mask ; this is not possible")) ;
733 return FALSE ;
734 }
735 wxBitmap myBitmap (width, height) ;
736 wxMemoryDC memDC;
737 memDC.SelectObject( myBitmap );
738 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
739 memDC.SelectObject( wxNullBitmap );
740 DoDrawBitmap(myBitmap, xdest, ydest);
741 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoBlit Call executed")) ;
742 return FALSE ;
743}
744
745
746void wxSVGFileDC::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
747{
748 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() ) ;
749 wxMemoryDC memDC;
750 memDC.SelectObject( myBitmap );
751 memDC.DrawIcon(myIcon,0,0);
752 memDC.SelectObject( wxNullBitmap );
753 DoDrawBitmap(myBitmap, x, y);
754 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawIcon Call executed")) ;
755 return ;
756}
757
758
759
760void wxSVGFileDC::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool bTransparent /*=0*/ )
761{
762 if (m_graphics_changed) NewGraphics ();
763
764 wxString sTmp, s, sPNG ;
765 wxImage::AddHandler(new wxPNGHandler);
766
767// create suitable file name
768 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
769 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
770 while (wxFile::Exists(sPNG) )
771 {
772 m_sub_images ++ ;
773 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
774 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
775 }
776
777//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
778 wxBitmap myBitmap = bmp ;
779//save it
780 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
781
782// refrence the bitmap from the SVG doc
783 int w = myBitmap.GetWidth();
784 int h = myBitmap.GetHeight();
785 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
786 s = s + sTmp ;
787 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
788 s = s + sTmp + wxT("<title>Image from wxSVG</title> </image>") + newline;
789
790 if (m_OK && bPNG_OK)
791 {
792 m_outfile->Write (s.c_str(), s.Len() ) ;
793 }
794 m_OK = m_outfile->Ok () && bPNG_OK;
795 wxASSERT_MSG(!wxSVG_DEBUG, wxT("wxSVGFileDC::DoDrawBitmap Call executed")) ;
796
797 return ;
798}
799
800
801// ---------------------------------------------------------------------------
802// coordinates transformations
803// ---------------------------------------------------------------------------
804
805wxCoord wxSVGFileDC::DeviceToLogicalX(wxCoord x) const
806{
807 return XDEV2LOG(x);
808}
809
810
811wxCoord wxSVGFileDC::DeviceToLogicalY(wxCoord y) const
812{
813 return YDEV2LOG(y);
814}
815
816
817wxCoord wxSVGFileDC::DeviceToLogicalXRel(wxCoord x) const
818{
819 return XDEV2LOGREL(x);
820}
821
822
823wxCoord wxSVGFileDC::DeviceToLogicalYRel(wxCoord y) const
824{
825 return YDEV2LOGREL(y);
826}
827
828
829wxCoord wxSVGFileDC::LogicalToDeviceX(wxCoord x) const
830{
831 return XLOG2DEV(x);
832}
833
834
835wxCoord wxSVGFileDC::LogicalToDeviceY(wxCoord y) const
836{
837 return YLOG2DEV(y);
838}
839
840
841wxCoord wxSVGFileDC::LogicalToDeviceXRel(wxCoord x) const
842{
843 return XLOG2DEVREL(x);
844}
845
846
847wxCoord wxSVGFileDC::LogicalToDeviceYRel(wxCoord y) const
848{
849 return YLOG2DEVREL(y);
850}
851
852
853#ifdef __BORLANDC__
854#pragma warn .rch
855#pragma warn .ccc
856#endif