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