///////////////////////////////////////////////////////////////////////////// // Name: svg.cpp // Purpose: SVG plot // Author: Chris Elliott // Modified by: JP Charras (dec 2006) // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include <wx/wxprec.h> #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include <wx/wx.h> #endif #if wxCHECK_VERSION( 2, 9, 0 ) // Do nothing, because wxWidgets 3 supports the SVG format // previously, was a contribution library, not included in wxWidgets base #else #include <dcsvg.h> #include <wx/image.h> #include <macros.h> #define wxSVG_DEBUG false // or true to see the calls being executed #define newline wxString( wxT( "\n" ) ) #define space wxString( wxT( " " ) ) #define semicolon wxString( wxT( ";" ) ) #ifdef __BORLANDC__ #pragma warn -rch #pragma warn -ccc #endif /* some define not included in early wxWidget versions: */ #ifndef twips2mm #define twips2mm 0.0176388888889 #endif #ifndef pt2mm #define pt2mm 0.352777777778 #endif static inline double DegToRad( double deg ) { return (deg * M_PI) / 180.0; } wxString wxColStr( wxColour c ) { unsigned char r, g, b; r = c.Red(); g = c.Green(); b = c.Blue(); // possible Unicode bug here wxString s = wxDecToHex( r ) + wxDecToHex( g ) + wxDecToHex( b ); return s; } wxString wxBrushString( wxColour c, int style ) { wxString s = wxT( "fill:#" ) + wxColStr( c ) + semicolon + space; switch( style ) { case wxSOLID: s = s + wxT( "fill-opacity:1.0; " ); break; case wxTRANSPARENT: s = s + wxT( "fill-opacity:0.0; " ); break; default: wxASSERT_MSG( false, wxT( "wxSVGFileDC::Requested Brush Style not available" ) ); } s = s + newline; return s; } /***********************************************************************/ void wxSVGFileDC::Init( wxString f, int Width, int Height, float dpi ) /***********************************************************************/ /* set up things first wxDCBase does all this? */ { m_width = Width; m_height = Height; m_clipping = false; m_OK = true; m_mm_to_pix_x = dpi / 25.4; m_mm_to_pix_y = dpi / 25.4; m_signX = m_signY = 1; m_userScaleX = m_userScaleY = m_deviceOriginX = m_deviceOriginY = 0; m_OriginX = m_OriginY = 0; m_logicalOriginX = m_logicalOriginY = 0; m_logicalScaleX = m_logicalScaleY = 0; m_scaleX = m_scaleY = 1.0; m_logicalFunction = wxCOPY; m_backgroundMode = wxTRANSPARENT; m_mappingMode = wxMM_TEXT; m_backgroundBrush = *wxTRANSPARENT_BRUSH; m_textForegroundColour = *wxBLACK; m_textBackgroundColour = *wxWHITE; m_colour = wxColourDisplay(); m_pen = *wxBLACK_PEN; m_font = *wxNORMAL_FONT; m_brush = *wxWHITE_BRUSH; m_graphics_changed = true; ////////////////////code here m_outfile = new wxFileOutputStream( f ); m_OK = m_outfile->Ok(); if( m_OK ) { m_filename = f; m_sub_images = 0; wxString s; s = wxT( "<?xml version=\"1.0\" standalone=\"no\"?>" ); s = s + newline; write( s ); s = wxT( "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " ) + newline; write( s ); s = wxT( "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> " ) + newline; write( s ); s.Printf( wxT( "<svg\n" ) ); write( s ); s.Printf( wxT( " xmlns=\"http://www.w3.org/2000/svg\"\n" ) ); write( s ); s.Printf( wxT( " version=\"1.1\"\n" ) ); write( s ); s.Printf( wxT( " width=\"%gin\" height=\"%gin\" viewBox=\"0 0 %d %d \"\n" ), double (Width) / dpi, double (Height) / dpi, Width, Height ); write( s ); s.Printf( wxT( ">\n" ) ); write( s ); s = wxT( " <title>SVG Picture created as " ) + wxFileNameFromPath( f ) + wxT( " </title>" ) + newline; write( s ); s = wxString( wxT( " <desc>Picture generated by wxSVG " ) ) + wxSVGVersion + wxT( " </desc>" ) + newline; write( s ); s = wxT( " <g style=\"fill:black; stroke:black; stroke-width:1\">" ) + newline; write( s ); } } // constructors wxSVGFileDC::wxSVGFileDC( wxString f ) { // quarter 640x480 screen display at 72 dpi Init( f, 320, 240, 72.0 ); } wxSVGFileDC::wxSVGFileDC( wxString f, int Width, int Height ) { Init( f, Width, Height, 72.0 ); } wxSVGFileDC::wxSVGFileDC( wxString f, int Width, int Height, float dpi ) { Init( f, Width, Height, dpi ); } wxSVGFileDC::~wxSVGFileDC() { wxString s = wxT( "</g> \n</svg> \n" ); write( s ); delete m_outfile; } ////////////////////////////////////////////////////////////////////////////////////////// void wxSVGFileDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { if( m_graphics_changed ) NewGraphics(); wxString s; s.Printf( wxT( "<path d=\"M%d %d L%d %d\" /> \n" ), x1, y1, x2, y2 ); if( m_OK ) { write( s ); } wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DrawLine Call executed" ) ); CalcBoundingBox( x1, y1 ); CalcBoundingBox( x2, y2 ); return; } void wxSVGFileDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) { for( int i = 1; i < n; i++ ) { DoDrawLine( points[i - 1].x + xoffset, points[i - 1].y + yoffset, points[ i ].x + xoffset, points[ i ].y + yoffset ); } } void wxSVGFileDC::DoDrawPoint( wxCoord x1, wxCoord y1 ) { wxString s; if( m_graphics_changed ) NewGraphics(); s = wxT( "<g style = \"stroke-linecap:round;\" > " ) + newline; write( s ); DrawLine( x1, y1, x1, y1 ); s = wxT( "</g>" ); write( s ); } void wxSVGFileDC::DoDrawCheckMark( wxCoord x1, wxCoord y1, wxCoord width, wxCoord height ) { wxDCBase::DoDrawCheckMark( x1, y1, width, height ); } void wxSVGFileDC::DoDrawText( const wxString& text, wxCoord x1, wxCoord y1 ) { DoDrawRotatedText( text, x1, y1, 0.0 ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DrawText Call executed" ) ); } void wxSVGFileDC::DoDrawRotatedText( const wxString& sText, wxCoord x, wxCoord y, double angle ) { //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW if( m_graphics_changed ) NewGraphics(); wxString s, sTmp; // calculate bounding box wxCoord w, h, desc; DoGetTextExtent( sText, &w, &h, &desc ); double rad = DegToRad( angle ); // wxT("upper left") and wxT("upper right") CalcBoundingBox( x, y ); CalcBoundingBox( (wxCoord) ( x + w * cos( rad ) ), (wxCoord) ( y - h * sin( rad ) ) ); // wxT("bottom left") and wxT("bottom right") x += (wxCoord) ( h * sin( rad ) ); y += (wxCoord) ( h * cos( rad ) ); CalcBoundingBox( x, y ); CalcBoundingBox( (wxCoord) ( x + h * sin( rad ) ), (wxCoord) ( y + h * cos( rad ) ) ); if( m_backgroundMode == wxSOLID ) { // draw background first // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::Draw Rotated Text Call plotting text background" ) ); sTmp.Printf( wxT( " <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" " ), x, y + desc - h, w, h ); s = sTmp + wxT( "style=\"fill:#" ) + wxColStr( m_textBackgroundColour ) + wxT( "; " ); s = s + wxT( "stroke-width:1; stroke:#" ) + wxColStr( m_textBackgroundColour ) + wxT( "; " ); sTmp.Printf( wxT( "\" transform=\"rotate( %.2g %d %d ) \">" ), -angle, x, y ); s = s + sTmp + newline; write( s ); } //now do the text itself s.Printf( wxT( " <text x=\"%d\" y=\"%d\" " ), x, y ); sTmp = m_font.GetFaceName(); if( sTmp.Len() > 0 ) s = s + wxT( "style=\"font-family:" ) + sTmp + wxT( "; " ); else s = s + wxT( "style=\" " ); wxString fontweights[3] = { wxT( "normal" ), wxT( "lighter" ), wxT( "bold" ) }; s = s + wxT( "font-weight:" ) + fontweights[m_font.GetWeight() - wxNORMAL] + semicolon + space; wxString fontstyles[5] = { wxT( "normal" ), wxT( "style error" ), wxT( "style error" ), wxT( "italic" ), wxT( "oblique" ) }; s = s + wxT( "font-style:" ) + fontstyles[m_font.GetStyle() - wxNORMAL] + semicolon + space; sTmp.Printf( wxT( "font-size:%dpt; fill:#" ), m_font.GetPointSize() ); s = s + sTmp; s = s + wxColStr( m_textForegroundColour ) + wxT( "; stroke:#" ) + wxColStr( m_textForegroundColour ) + wxT( "; " ); sTmp.Printf( wxT( "stroke-width:0;\" transform=\"rotate( %.2g %d %d ) \" >" ), -angle, x, y ); s = s + sTmp + sText + wxT( "</text> " ) + newline; if( m_OK ) { write( s ); } wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DrawRotatedText Call executed" ) ); } void wxSVGFileDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { DoDrawRoundedRectangle( x, y, width, height, 0 ); } void wxSVGFileDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) { if( m_graphics_changed ) NewGraphics(); wxString s; s.Printf( wxT( " <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%.2g\" " ), x, y, width, height, radius ); s = s + wxT( " /> " ) + newline; write( s ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawRoundedRectangle Call executed" ) ); CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } void wxSVGFileDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle ) { if( m_graphics_changed ) NewGraphics(); wxString s, sTmp; s = wxT( "<polygon style=\"" ); if( fillStyle == wxODDEVEN_RULE ) s = s + wxT( "fill-rule:evenodd; " ); else s = s + wxT( "fill-rule:nonzero; " ); s = s + wxT( "\" \npoints=\"" ); for( int i = 0; i < n; i++ ) { sTmp.Printf( wxT( "%d,%d" ), points[i].x + xoffset, points[i].y + yoffset ); s = s + sTmp + newline; CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset ); } s = s + wxT( "\" /> " ); s = s + newline; write( s ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawPolygon Call executed" ) ); } void wxSVGFileDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { if( m_graphics_changed ) NewGraphics(); int rh = height / 2; int rw = width / 2; wxString s; s.Printf( wxT( "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" " ), x + rw, y + rh, rw, rh ); s = s + wxT( " /> " ) + newline; write( s ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawEllipse Call executed" ) ); CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } void wxSVGFileDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc ) { /* Draws an arc of a circle, centred on (xc, yc), with starting point * (x1, y1) and ending at (x2, y2). The current pen is used for the outline * and the current brush for filling the shape. * * The arc is drawn in an anticlockwise direction from the start point to * the end point. */ if( m_graphics_changed ) NewGraphics(); wxString s; // we need the radius of the circle which has two estimates double r1 = sqrt( double ( (x1 - xc) * (x1 - xc) ) + double ( (y1 - yc) * (y1 - yc) ) ); double r2 = sqrt( double ( (x2 - xc) * (x2 - xc) ) + double ( (y2 - yc) * (y2 - yc) ) ); wxASSERT_MSG( (fabs( r2 - r1 ) <= 3), wxT( "wxSVGFileDC::DoDrawArc Error in getting radii of circle" ) ); if( fabs( r2 - r1 ) > 3 ) //pixels { s = wxT( "<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n" ); write( s ); } double theta1 = atan2( (double) (yc - y1), (double) (x1 - xc) ); if( theta1 < 0 ) theta1 = theta1 + M_PI * 2; double theta2 = atan2( (double) (yc - y2), (double) (x2 - xc) ); if( theta2 < 0 ) theta2 = theta2 + M_PI * 2; if( theta2 < theta1 ) theta2 = theta2 + M_PI * 2; int fArc; // flag for large or small arc 0 means less than 180 degrees if( fabs( theta2 - theta1 ) > M_PI ) fArc = 1;else fArc = 0; int fSweep; if( (theta2 - theta1) > 0 ) fSweep = 0;else fSweep = 1; float Axis_rotation = 0.0; // Draw arc as pie: // s.Printf ( wxT("<path d=\"M%d %d A%.2g %.2g 0.0 %d %d %d %d L%d %d z "), // the z means close the path and fill (usefull to draw a pie) // x1, y1, r1, r2, fArc, fSweep, x2, y2, xc ,yc ); // Draw a single arc: s.Printf( wxT( "<path d=\"M%d %d A%.2g %.2g %g %d %d %d %d" ), x1, y1, r1, r2, Axis_rotation, fArc, fSweep, x2, y2 ); s = s + wxT( " \" /> " ) + newline; if( m_OK ) { write( s ); } wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawArc Call executed" ) ); } void wxSVGFileDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, double sa, double ea ) { /* * Draws an arc of an ellipse. The current pen is used for drawing the arc * and the current brush is used for drawing the pie. This function is * currently only available for X window and PostScript device contexts. * * x and y specify the x and y coordinates of the upper-left corner of the * rectangle that contains the ellipse. * * width and height specify the width and height of the rectangle that * contains the ellipse. * * start and end specify the start and end of the arc relative to the * three-o'clock position from the center of the rectangle. Angles are * specified in degrees (360 is a complete circle). Positive values mean * counter-clockwise motion. If start is equal to end, a complete ellipse * will be drawn. */ //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW if( m_graphics_changed ) NewGraphics(); wxString s; //radius double rx = w / 2; double ry = h / 2; // center double xc = x + rx; double yc = y + ry; double xs, ys, xe, ye; xs = xc + rx* cos( DegToRad (sa) ); xe = xc + rx* cos( DegToRad (ea) ); ys = yc - ry* sin( DegToRad (sa) ); ye = yc - ry* sin( DegToRad (ea) ); ///now same as circle arc... double theta1 = atan2( ys - yc, xs - xc ); double theta2 = atan2( ye - yc, xe - xc ); int fArc; // flag for large or small arc 0 means less than 180 degrees if( fabs( theta2 - theta1 ) > M_PI ) fArc = 1;else fArc = 0; int fSweep; if( (theta2 - theta1) > 0 ) fSweep = 0;else fSweep = 1; float Axis_rotation = 0.0; // Draw a single arc: s.Printf( wxT( "<path d=\"M%d,%d A%d,%d %g %d %d %d,%d" ), int (xs), int (ys), int (rx), int (ry), Axis_rotation, fArc, fSweep, int (xe), int (ye) ); s = s + wxT( " \" /> " ) + newline; if( m_OK ) { write( s ); } wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawEllipticArc Call executed" ) ); } void wxSVGFileDC::DoGetTextExtent( const wxString& string, wxCoord* w, wxCoord* h, wxCoord* descent, wxCoord* externalLeading, wxFont* font ) const { wxScreenDC sDC; sDC.SetFont( m_font ); if( font != NULL ) sDC.SetFont( *font ); sDC.GetTextExtent( string, w, h, descent, externalLeading ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::GetTextExtent Call executed" ) ); } wxCoord wxSVGFileDC::GetCharHeight() const { wxScreenDC sDC; sDC.SetFont( m_font ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::GetCharHeight Call executing" ) ); return sDC.GetCharHeight(); } wxCoord wxSVGFileDC::GetCharWidth() const { wxScreenDC sDC; sDC.SetFont( m_font ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::GetCharWidth Call executing" ) ); return sDC.GetCharWidth(); } /// Set Functions ///////////////////////////////////////////////////////////////// void wxSVGFileDC::SetBackground( const wxBrush& brush ) { m_backgroundBrush = brush; return; } void wxSVGFileDC::SetBackgroundMode( int mode ) { m_backgroundMode = mode; return; } void wxSVGFileDC::SetBrush( const wxBrush& brush ) { m_brush = brush; m_graphics_changed = true; wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::SetBrush Call executed" ) ); } void wxSVGFileDC::SetPen( const wxPen& pen ) { // width, color, ends, joins : currently implemented // dashes, stipple : not implemented m_pen = pen; m_graphics_changed = true; wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::SetPen Call executed" ) ); } void wxSVGFileDC::NewGraphics() { int w = m_pen.GetWidth(); wxColour c = m_pen.GetColour(); wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn; sBrush = wxT( "</g>\n<g style=\"" ) + wxBrushString( m_brush.GetColour(), m_brush.GetStyle() ) + wxT( " stroke:#" ) + wxColStr( c ) + wxT( "; " ); switch( m_pen.GetCap() ) { case wxCAP_PROJECTING: sPenCap = wxT( "stroke-linecap:square; " ); break; case wxCAP_BUTT: sPenCap = wxT( "stroke-linecap:butt; " ); break; case wxCAP_ROUND: default: sPenCap = wxT( "stroke-linecap:round; " ); } ; switch( m_pen.GetJoin() ) { case wxJOIN_BEVEL: sPenJoin = wxT( "stroke-linejoin:bevel; " ); break; case wxJOIN_MITER: sPenJoin = wxT( "stroke-linejoin:miter; " ); break; case wxJOIN_ROUND: default: sPenJoin = wxT( "stroke-linejoin:round; " ); } ; switch( m_pen.GetStyle() ) { case wxSOLID: sPenStyle = wxT( "stroke-opacity:1.0; stroke-opacity:1.0; " ); break; case wxTRANSPARENT: sPenStyle = wxT( "stroke-opacity:0.0; stroke-opacity:0.0; " ); break; default: wxASSERT_MSG( false, wxT( "wxSVGFileDC::SetPen Call called to set a Style which is not available" ) ); sWarn = sWarn + wxT( "<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n" ); } sLast.Printf( wxT( "stroke-width:%d\" \n transform=\"translate(%.2g %.2g) scale(%.2g %.2g)\">" ), w, m_OriginX, m_OriginY, m_scaleX, m_scaleY ); s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + newline + sWarn; write( s ); m_graphics_changed = false; wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::NewGraphics Call executed" ) ); } void wxSVGFileDC::SetFont( const wxFont& font ) { m_font = font; wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::SetFont Call executed" ) ); } void wxSVGFileDC::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; m_scaleY = m_logicalScaleY * m_userScaleY; m_OriginX = m_logicalOriginX * m_logicalScaleX + m_deviceOriginX; m_OriginY = m_logicalOriginY * m_logicalScaleY + m_deviceOriginY; m_graphics_changed = true; } int wxSVGFileDC::GetMapMode() { return m_mappingMode; } void wxSVGFileDC::SetMapMode( int mode ) { switch( mode ) { case wxMM_TWIPS: SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); break; case wxMM_POINTS: SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); break; case wxMM_METRIC: SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); break; case wxMM_LOMETRIC: SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); break; default: case wxMM_TEXT: SetLogicalScale( 1.0, 1.0 ); break; } m_mappingMode = mode; /* we don't do this mega optimisation * if (mode != wxMM_TEXT) * { * m_needComputeScaleX = true; * m_needComputeScaleY = true; * } */ } void wxSVGFileDC::GetUserScale( double* x, double* y ) const { *x = m_userScaleX; *y = m_userScaleY; } void wxSVGFileDC::SetUserScale( double x, double y ) { // allow negative ? -> no m_userScaleX = x; m_userScaleY = y; ComputeScaleAndOrigin(); } void wxSVGFileDC::SetLogicalScale( double x, double y ) { // allow negative ? m_logicalScaleX = x; m_logicalScaleY = y; ComputeScaleAndOrigin(); } void wxSVGFileDC::SetLogicalOrigin( wxCoord x, wxCoord y ) { // is this still correct ? m_logicalOriginX = x * m_signX; m_logicalOriginY = y * m_signY; ComputeScaleAndOrigin(); } void wxSVGFileDC::SetDeviceOrigin( wxCoord x, wxCoord y ) { // only wxPostScripDC has m_signX = -1, m_deviceOriginX = x; m_deviceOriginY = y; ComputeScaleAndOrigin(); } void wxSVGFileDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) { // only wxPostScripDC has m_signX = -1, m_signX = (xLeftRight ? 1 : -1); m_signY = (yBottomUp ? -1 : 1); ComputeScaleAndOrigin(); } // export a bitmap as a raster image in png bool wxSVGFileDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC* source, wxCoord xsrc, wxCoord ysrc, int logicalFunc /*= wxCOPY*/, bool useMask /*= false*/, wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/ ) { if( logicalFunc != wxCOPY ) { wxASSERT_MSG( false, wxT( "wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible" ) ); return false; } if( useMask != false ) { wxASSERT_MSG( false, wxT( "wxSVGFileDC::DoBlit Call requested False mask ; this is not possible" ) ); return false; } wxBitmap myBitmap( width, height ); wxMemoryDC memDC; memDC.SelectObject( myBitmap ); memDC.Blit( 0, 0, width, height, source, xsrc, ysrc ); memDC.SelectObject( wxNullBitmap ); DoDrawBitmap( myBitmap, xdest, ydest ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoBlit Call executed" ) ); return false; } void wxSVGFileDC::DoDrawIcon( const class wxIcon& myIcon, wxCoord x, wxCoord y ) { wxBitmap myBitmap( myIcon.GetWidth(), myIcon.GetHeight() ); wxMemoryDC memDC; memDC.SelectObject( myBitmap ); memDC.DrawIcon( myIcon, 0, 0 ); memDC.SelectObject( wxNullBitmap ); DoDrawBitmap( myBitmap, x, y ); wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawIcon Call executed" ) ); return; } void wxSVGFileDC::DoDrawBitmap( const class wxBitmap& bmp, wxCoord x, wxCoord y, bool bTransparent /*=0*/ ) { if( m_graphics_changed ) NewGraphics(); wxString sTmp, s, sPNG; wxImage::AddHandler( new wxPNGHandler ); // create suitable file name sTmp.Printf( wxT( "_image%d.png" ), m_sub_images ); sPNG = m_filename.BeforeLast( wxT( '.' ) ) + sTmp; while( wxFile::Exists( sPNG ) ) { m_sub_images++; sTmp.Printf( wxT( "_image%d.png" ), m_sub_images ); sPNG = m_filename.BeforeLast( wxT( '.' ) ) + sTmp; } //create copy of bitmap (wxGTK doesn't like saving a constant bitmap) wxBitmap myBitmap = bmp; //save it bool bPNG_OK = myBitmap.SaveFile( sPNG, wxBITMAP_TYPE_PNG ); // refrence the bitmap from the SVG doc int w = myBitmap.GetWidth(); int h = myBitmap.GetHeight(); sTmp.Printf( wxT( " <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" " ), x, y, w, h ); s = s + sTmp; sTmp.Printf( wxT( " xlink:href=\"%s\"> \n" ), GetChars( sPNG ) ); s = s + sTmp + wxT( "<title>Image from wxSVG</title> </image>" ) + newline; if( m_OK && bPNG_OK ) { write( s ); } m_OK = m_outfile->Ok() && bPNG_OK; wxASSERT_MSG( !wxSVG_DEBUG, wxT( "wxSVGFileDC::DoDrawBitmap Call executed" ) ); return; } // --------------------------------------------------------------------------- // coordinates transformations // --------------------------------------------------------------------------- wxCoord wxSVGFileDC::DeviceToLogicalX( wxCoord x ) const { return XDEV2LOG( x ); } wxCoord wxSVGFileDC::DeviceToLogicalY( wxCoord y ) const { return YDEV2LOG( y ); } wxCoord wxSVGFileDC::DeviceToLogicalXRel( wxCoord x ) const { return XDEV2LOGREL( x ); } wxCoord wxSVGFileDC::DeviceToLogicalYRel( wxCoord y ) const { return YDEV2LOGREL( y ); } wxCoord wxSVGFileDC::LogicalToDeviceX( wxCoord x ) const { return XLOG2DEV( x ); } wxCoord wxSVGFileDC::LogicalToDeviceY( wxCoord y ) const { return YLOG2DEV( y ); } wxCoord wxSVGFileDC::LogicalToDeviceXRel( wxCoord x ) const { return XLOG2DEVREL( x ); } wxCoord wxSVGFileDC::LogicalToDeviceYRel( wxCoord y ) const { return YLOG2DEVREL( y ); } void wxSVGFileDC::write( const wxString& s ) { const wxWX2MBbuf buf = s.mb_str( wxConvUTF8 ); m_outfile->Write( buf, strlen( (const char*) buf ) ); m_OK = m_outfile->Ok(); } #ifdef __BORLANDC__ #pragma warn .rch #pragma warn .ccc #endif #endif // wxCHECK_VERSION