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