1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/svg.cpp
4 // Author: Chris Elliott
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
21 #include "wx/dcmemory.h"
22 #include "wx/dcscreen.h"
28 #include "wx/wfstream.h"
29 #include "wx/filename.h"
31 #define wxSVG_DEBUG false
32 // or true to see the calls being executed
34 // ----------------------------------------------------------
36 // ----------------------------------------------------------
41 inline double DegToRad(double deg
) { return (deg
* M_PI
) / 180.0; }
43 wxString
wxBrushString ( wxColour c
, int style
)
45 wxString s
= wxT("fill:") + c
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
48 case wxBRUSHSTYLE_SOLID
:
49 s
= s
+ wxT("fill-opacity:1.0; ");
51 case wxBRUSHSTYLE_TRANSPARENT
:
52 s
= s
+ wxT("fill-opacity:0.0; ");
56 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
63 // This function returns a string representation of a floating point number in
64 // C locale (i.e. always using "." for the decimal separator) and with the
65 // fixed precision (which is 2 for some unknown reason but this is what it was
66 // in this code originally).
67 inline wxString
NumStr(double f
)
69 return wxString::FromCDouble(f
, 2);
72 } // anonymous namespace
74 // ----------------------------------------------------------
76 // ----------------------------------------------------------
78 IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl
, wxDC
)
80 wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC
*owner
, const wxString
&filename
,
81 int width
, int height
, double dpi
) :
84 Init( filename
, width
, height
, dpi
);
87 void wxSVGFileDCImpl::Init (const wxString
&filename
, int Width
, int Height
, double dpi
)
96 m_mm_to_pix_x
= dpi
/25.4;
97 m_mm_to_pix_y
= dpi
/25.4;
99 m_backgroundBrush
= *wxTRANSPARENT_BRUSH
;
100 m_textForegroundColour
= *wxBLACK
;
101 m_textBackgroundColour
= *wxWHITE
;
102 m_colour
= wxColourDisplay();
104 m_pen
= *wxBLACK_PEN
;
105 m_font
= *wxNORMAL_FONT
;
106 m_brush
= *wxWHITE_BRUSH
;
108 m_graphics_changed
= true;
110 ////////////////////code here
112 m_outfile
= new wxFileOutputStream(filename
);
113 m_OK
= m_outfile
->Ok ();
116 m_filename
= filename
;
119 s
= wxT("<?xml version=\"1.0\" standalone=\"no\"?>") + wxString(wxT("\n"));
121 s
= wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + wxString(wxT("\n"));
123 s
= wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + wxString(wxT("\n"));
125 s
= wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + wxString(wxT("\n"));
127 s
.Printf( wxT(" width=\"%scm\" height=\"%scm\" viewBox=\"0 0 %d %d \"> \n"), NumStr(float(Width
)/dpi
*2.54), NumStr(float(Height
)/dpi
*2.54), Width
, Height
);
129 s
= wxT("<title>SVG Picture created as ") + wxFileName(filename
).GetFullName() + wxT(" </title>") + wxT("\n");
131 s
= wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion
+ wxT(" </desc>")+ wxT("\n");
133 s
= wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + wxString(wxT("\n"));
138 wxSVGFileDCImpl::~wxSVGFileDCImpl()
140 wxString s
= wxT("</g> \n</svg> \n");
145 void wxSVGFileDCImpl::DoGetSizeMM( int *width
, int *height
) const
148 *width
= wxRound( (double)m_width
/ m_mm_to_pix_x
);
151 *height
= wxRound( (double)m_height
/ m_mm_to_pix_y
);
154 wxSize
wxSVGFileDCImpl::GetPPI() const
156 return wxSize( wxRound(m_dpi
), wxRound(m_dpi
) );
159 void wxSVGFileDCImpl::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
161 if (m_graphics_changed
) NewGraphics ();
163 s
.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1
,y1
,x2
,y2
);
168 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawLine Call executed"));
169 CalcBoundingBox(x1
, y1
);
170 CalcBoundingBox(x2
, y2
);
174 void wxSVGFileDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
176 for ( int i
= 1; i
< n
; i
++ )
178 DoDrawLine ( points
[i
-1].x
+ xoffset
, points
[i
-1].y
+ yoffset
,
179 points
[ i
].x
+ xoffset
, points
[ i
].y
+ yoffset
);
183 void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1
, wxCoord y1
)
186 if (m_graphics_changed
) NewGraphics ();
187 s
= wxT("<g style = \"stroke-linecap:round;\" > ") + wxString(wxT("\n"));
189 DoDrawLine ( x1
,y1
,x1
,y1
);
194 void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, wxCoord width
, wxCoord height
)
196 wxDCImpl::DoDrawCheckMark (x1
,y1
,width
,height
);
199 void wxSVGFileDCImpl::DoDrawText(const wxString
& text
, wxCoord x1
, wxCoord y1
)
201 DoDrawRotatedText(text
, x1
,y1
,0.0);
202 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawText Call executed"));
205 void wxSVGFileDCImpl::DoDrawRotatedText(const wxString
& sText
, wxCoord x
, wxCoord y
, double angle
)
207 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
208 if (m_graphics_changed
) NewGraphics ();
211 // calculate bounding box
213 DoGetTextExtent(sText
, &w
, &h
, &desc
);
215 double rad
= DegToRad(angle
);
217 // wxT("upper left") and wxT("upper right")
218 CalcBoundingBox(x
, y
);
219 CalcBoundingBox((wxCoord
)(x
+ w
*cos(rad
)), (wxCoord
)(y
- h
*sin(rad
)));
221 // wxT("bottom left") and wxT("bottom right")
222 x
+= (wxCoord
)(h
*sin(rad
));
223 y
+= (wxCoord
)(h
*cos(rad
));
224 CalcBoundingBox(x
, y
);
225 CalcBoundingBox((wxCoord
)(x
+ h
*sin(rad
)), (wxCoord
)(y
+ h
*cos(rad
)));
227 if (m_backgroundMode
== wxBRUSHSTYLE_SOLID
)
229 // draw background first
230 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
232 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background"));
233 sTmp
.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x
,y
+desc
-h
, w
, h
);
234 s
= sTmp
+ wxT("style=\"fill:") + m_textBackgroundColour
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
235 s
= s
+ wxT("stroke-width:1; stroke:") + m_textBackgroundColour
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
236 sTmp
.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \">"), NumStr(-angle
), x
,y
);
237 s
= s
+ sTmp
+ wxT("\n");
240 //now do the text itself
241 s
.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x
,y
);
243 sTmp
= m_font
.GetFaceName ();
244 if (sTmp
.Len () > 0) s
= s
+ wxT("style=\"font-family:") + sTmp
+ wxT("; ");
245 else s
= s
+ wxT("style=\" ");
247 wxString fontweights
[3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
248 s
= s
+ wxT("font-weight:") + fontweights
[m_font
.GetWeight() - wxNORMAL
] + wxT("; ");
250 wxString fontstyles
[5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
251 s
= s
+ wxT("font-style:") + fontstyles
[m_font
.GetStyle() - wxNORMAL
] + wxT("; ");
253 sTmp
.Printf (wxT("font-size:%dpt; fill:"), m_font
.GetPointSize () );
255 s
= s
+ m_textForegroundColour
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; stroke:") + m_textForegroundColour
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
256 sTmp
.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle
), x
,y
);
257 s
= s
+ sTmp
+ sText
+ wxT("</text> ") + wxT("\n");
262 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawRotatedText Call executed"));
265 void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
267 DoDrawRoundedRectangle(x
, y
, width
, height
, 0);
270 void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
273 if (m_graphics_changed
) NewGraphics ();
276 s
.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
277 x
, y
, width
, height
, NumStr(radius
) );
279 s
= s
+ wxT(" /> ") + wxT("\n");
282 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed"));
283 CalcBoundingBox(x
, y
);
284 CalcBoundingBox(x
+ width
, y
+ height
);
287 void wxSVGFileDCImpl::DoDrawPolygon(int n
, wxPoint points
[],
288 wxCoord xoffset
, wxCoord yoffset
,
289 wxPolygonFillMode fillStyle
)
291 if (m_graphics_changed
) NewGraphics ();
293 s
= wxT("<polygon style=\"");
294 if ( fillStyle
== wxODDEVEN_RULE
)
295 s
= s
+ wxT("fill-rule:evenodd; ");
297 s
= s
+ wxT("fill-rule:nonzero; ");
299 s
= s
+ wxT("\" \npoints=\"");
301 for (int i
= 0; i
< n
; i
++)
303 sTmp
.Printf ( wxT("%d,%d"), points
[i
].x
+xoffset
, points
[i
].y
+yoffset
);
304 s
= s
+ sTmp
+ wxT("\n");
305 CalcBoundingBox ( points
[i
].x
+xoffset
, points
[i
].y
+yoffset
);
307 s
= s
+ wxT("\" /> ");
311 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawPolygon Call executed"));
314 void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
317 if (m_graphics_changed
) NewGraphics ();
323 s
.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x
+rw
,y
+rh
, rw
, rh
);
324 s
= s
+ wxT(" /> ") + wxT("\n");
328 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawEllipse Call executed"));
329 CalcBoundingBox(x
, y
);
330 CalcBoundingBox(x
+ width
, y
+ height
);
333 void wxSVGFileDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
)
335 /* Draws an arc of a circle, centred on (xc, yc), with starting point
336 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
337 and the current brush for filling the shape.
339 The arc is drawn in an anticlockwise direction from the start point to
342 Might be better described as Pie drawing */
344 if (m_graphics_changed
) NewGraphics ();
347 // we need the radius of the circle which has two estimates
348 double r1
= sqrt ( double( (x1
-xc
)*(x1
-xc
) ) + double( (y1
-yc
)*(y1
-yc
) ) );
349 double r2
= sqrt ( double( (x2
-xc
)*(x2
-xc
) ) + double( (y2
-yc
)*(y2
-yc
) ) );
351 wxASSERT_MSG( (fabs ( r2
-r1
) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
352 if ( fabs ( r2
-r1
) > 3 ) //pixels
354 s
= wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
358 double theta1
= atan2((double)(yc
-y1
),(double)(x1
-xc
));
359 if ( theta1
< 0 ) theta1
= theta1
+ M_PI
* 2;
360 double theta2
= atan2((double)(yc
-y2
), (double)(x2
-xc
));
361 if ( theta2
< 0 ) theta2
= theta2
+ M_PI
* 2;
362 if ( theta2
< theta1
) theta2
= theta2
+ M_PI
*2;
364 int fArc
; // flag for large or small arc 0 means less than 180 degrees
365 if ( fabs(theta2
- theta1
) > M_PI
) fArc
= 1; else fArc
= 0;
367 int fSweep
= 0; // flag for sweep always 0
369 s
.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
370 x1
,y1
, NumStr(r1
), NumStr(r2
), fArc
, fSweep
, x2
, y2
, xc
, yc
);
372 // the z means close the path and fill
373 s
= s
+ wxT(" \" /> ") + wxT("\n");
381 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawArc Call executed"));
384 void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
387 Draws an arc of an ellipse. The current pen is used for drawing the arc
388 and the current brush is used for drawing the pie. This function is
389 currently only available for X window and PostScript device contexts.
391 x and y specify the x and y coordinates of the upper-left corner of the
392 rectangle that contains the ellipse.
394 width and height specify the width and height of the rectangle that
395 contains the ellipse.
397 start and end specify the start and end of the arc relative to the
398 three-o'clock position from the center of the rectangle. Angles are
399 specified in degrees (360 is a complete circle). Positive values mean
400 counter-clockwise motion. If start is equal to end, a complete ellipse
403 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
405 if (m_graphics_changed
) NewGraphics ();
415 double xs
, ys
, xe
, ye
;
416 xs
= xc
+ rx
* cos (DegToRad(sa
));
417 xe
= xc
+ rx
* cos (DegToRad(ea
));
418 ys
= yc
- ry
* sin (DegToRad(sa
));
419 ye
= yc
- ry
* sin (DegToRad(ea
));
421 ///now same as circle arc...
423 double theta1
= atan2(ys
-yc
, xs
-xc
);
424 double theta2
= atan2(ye
-yc
, xe
-xc
);
426 int fArc
; // flag for large or small arc 0 means less than 180 degrees
427 if ( (theta2
- theta1
) > 0 ) fArc
= 1; else fArc
= 0;
430 if ( fabs(theta2
- theta1
) > M_PI
) fSweep
= 1; else fSweep
= 0;
432 s
.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
433 int(xs
), int(ys
), int(rx
), int(ry
),
434 fArc
, fSweep
, int(xe
), int(ye
), int(xc
), int(yc
) );
437 s
= s
+ wxT(" \" /> ") + wxT("\n");
444 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed"));
447 void wxSVGFileDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*w
, wxCoord
*h
, wxCoord
*descent
, wxCoord
*externalLeading
, const wxFont
*font
) const
452 sDC
.SetFont (m_font
);
453 if ( font
!= NULL
) sDC
.SetFont ( *font
);
454 sDC
.GetTextExtent(string
, w
, h
, descent
, externalLeading
);
455 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetTextExtent Call executed"));
458 wxCoord
wxSVGFileDCImpl::GetCharHeight() const
462 sDC
.SetFont (m_font
);
464 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetCharHeight Call executing"));
465 return ( sDC
.GetCharHeight() );
469 wxCoord
wxSVGFileDCImpl::GetCharWidth() const
472 sDC
.SetFont (m_font
);
474 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetCharWidth Call executing"));
475 return ( sDC
.GetCharWidth() );
480 // ----------------------------------------------------------
481 // wxSVGFileDCImpl - set functions
482 // ----------------------------------------------------------
484 void wxSVGFileDCImpl::SetBackground( const wxBrush
&brush
)
487 m_backgroundBrush
= brush
;
492 void wxSVGFileDCImpl::SetBackgroundMode( int mode
)
494 m_backgroundMode
= mode
;
499 void wxSVGFileDCImpl::SetBrush(const wxBrush
& brush
)
504 m_graphics_changed
= true;
505 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetBrush Call executed"));
509 void wxSVGFileDCImpl::SetPen(const wxPen
& pen
)
511 // width, color, ends, joins : currently implemented
512 // dashes, stipple : not implemented
515 m_graphics_changed
= true;
516 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetPen Call executed"));
519 void wxSVGFileDCImpl::NewGraphics ()
522 int w
= m_pen
.GetWidth ();
523 wxColour c
= m_pen
.GetColour ();
525 wxString s
, sBrush
, sPenCap
, sPenJoin
, sPenStyle
, sLast
, sWarn
;
527 sBrush
= wxT("</g>\n<g style=\"") + wxBrushString ( m_brush
.GetColour (), m_brush
.GetStyle () )
528 + wxT(" stroke:") + c
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
530 switch ( m_pen
.GetCap () )
532 case wxCAP_PROJECTING
:
533 sPenCap
= wxT("stroke-linecap:square; ");
536 sPenCap
= wxT("stroke-linecap:butt; ");
540 sPenCap
= wxT("stroke-linecap:round; ");
542 switch ( m_pen
.GetJoin () )
545 sPenJoin
= wxT("stroke-linejoin:bevel; ");
548 sPenJoin
= wxT("stroke-linejoin:miter; ");
552 sPenJoin
= wxT("stroke-linejoin:round; ");
555 switch ( m_pen
.GetStyle () )
557 case wxPENSTYLE_SOLID
:
558 sPenStyle
= wxT("stroke-opacity:1.0; stroke-opacity:1.0; ");
560 case wxPENSTYLE_TRANSPARENT
:
561 sPenStyle
= wxT("stroke-opacity:0.0; stroke-opacity:0.0; ");
564 wxASSERT_MSG(false, wxT("wxSVGFileDC::SetPen Call called to set a Style which is not available"));
565 sWarn
= sWarn
+ wxT("<!--- wxSVGFileDC::SetPen Call called to set a Style which is not available --> \n");
568 sLast
.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
569 w
, NumStr(m_logicalOriginX
), NumStr(m_logicalOriginY
), NumStr(m_scaleX
), NumStr(m_scaleY
) );
571 s
= sBrush
+ sPenCap
+ sPenJoin
+ sPenStyle
+ sLast
+ wxT("\n") + sWarn
;
573 m_graphics_changed
= false;
574 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::NewGraphics Call executed"));
578 void wxSVGFileDCImpl::SetFont(const wxFont
& font
)
583 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetFont Call executed"));
586 // export a bitmap as a raster image in png
587 bool wxSVGFileDCImpl::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
588 wxDC
* source
, wxCoord xsrc
, wxCoord ysrc
,
589 wxRasterOperationMode logicalFunc
/*= wxCOPY*/, bool useMask
/*= false*/,
590 wxCoord
/*xsrcMask = -1*/, wxCoord
/*ysrcMask = -1*/)
592 if (logicalFunc
!= wxCOPY
)
594 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
597 if (useMask
!= false)
599 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
602 wxBitmap
myBitmap (width
, height
);
604 memDC
.SelectObject( myBitmap
);
605 memDC
.Blit(0, 0, width
, height
, source
, xsrc
, ysrc
);
606 memDC
.SelectObject( wxNullBitmap
);
607 DoDrawBitmap(myBitmap
, xdest
, ydest
);
608 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoBlit Call executed"));
612 void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon
& myIcon
, wxCoord x
, wxCoord y
)
614 wxBitmap
myBitmap (myIcon
.GetWidth(), myIcon
.GetHeight() );
616 memDC
.SelectObject( myBitmap
);
617 memDC
.DrawIcon(myIcon
,0,0);
618 memDC
.SelectObject( wxNullBitmap
);
619 DoDrawBitmap(myBitmap
, x
, y
);
620 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawIcon Call executed"));
624 void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap
& bmp
, wxCoord x
, wxCoord y
, bool WXUNUSED(bTransparent
) /*=0*/ )
626 if (m_graphics_changed
) NewGraphics ();
628 wxString sTmp
, s
, sPNG
;
629 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG
) == NULL
)
630 wxImage::AddHandler(new wxPNGHandler
);
632 // create suitable file name
633 sTmp
.Printf ( wxT("_image%d.png"), m_sub_images
);
634 sPNG
= m_filename
.BeforeLast(wxT('.')) + sTmp
;
635 while (wxFile::Exists(sPNG
) )
638 sTmp
.Printf ( wxT("_image%d.png"), m_sub_images
);
639 sPNG
= m_filename
.BeforeLast(wxT('.')) + sTmp
;
642 //create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
643 wxBitmap myBitmap
= bmp
;
645 bool bPNG_OK
= myBitmap
.SaveFile(sPNG
,wxBITMAP_TYPE_PNG
);
647 // reference the bitmap from the SVG doc
648 // only use filename & ext
649 sPNG
= sPNG
.AfterLast(wxFileName::GetPathSeparator());
651 // reference the bitmap from the SVG doc
652 int w
= myBitmap
.GetWidth();
653 int h
= myBitmap
.GetHeight();
654 sTmp
.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x
,y
,w
,h
);
656 sTmp
.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG
.c_str() );
657 s
= s
+ sTmp
+ wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
663 m_OK
= m_outfile
->Ok () && bPNG_OK
;
664 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawBitmap Call executed"));
669 void wxSVGFileDCImpl::write(const wxString
&s
)
671 const wxCharBuffer buf
= s
.utf8_str();
672 m_outfile
->Write(buf
, strlen((const char *)buf
));
673 m_OK
= m_outfile
->Ok();