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 // This function returns a string representation of a floating point number in
44 // C locale (i.e. always using "." for the decimal separator) and with the
45 // fixed precision (which is 2 for some unknown reason but this is what it was
46 // in this code originally).
47 inline wxString
NumStr(double f
)
49 return wxString::FromCDouble(f
, 2);
52 wxString
wxPenString(wxColour c
, int style
= wxPENSTYLE_SOLID
)
54 wxString s
= wxT("stroke:") + c
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
55 // Use the color's alpha value (if not opaque) for the opacity.
56 // Note that a transparent pen will override the alpha value.
57 if (c
.Alpha() != wxALPHA_OPAQUE
&& style
!= wxPENSTYLE_TRANSPARENT
)
59 s
+= wxString::Format(wxT("stroke-opacity:%s; "), NumStr(c
.Alpha()/255.));
65 case wxPENSTYLE_SOLID
:
66 s
+= wxT("stroke-opacity:1.0; ");
68 case wxPENSTYLE_TRANSPARENT
:
69 s
+= wxT("stroke-opacity:0.0; ");
72 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Pen Style not available"));
78 wxString
wxBrushString(wxColour c
, int style
= wxBRUSHSTYLE_SOLID
)
80 wxString s
= wxT("fill:") + c
.GetAsString(wxC2S_HTML_SYNTAX
) + wxT("; ");
81 // Use the color's alpha value (if not opaque) for the opacity.
82 // Note that a transparent brush will override the alpha value.
83 if (c
.Alpha() != wxALPHA_OPAQUE
&& style
!= wxBRUSHSTYLE_TRANSPARENT
)
85 s
+= wxString::Format(wxT("fill-opacity:%s; "), NumStr(c
.Alpha()/255.));
91 case wxBRUSHSTYLE_SOLID
:
92 s
+= wxT("fill-opacity:1.0; ");
94 case wxBRUSHSTYLE_TRANSPARENT
:
95 s
+= wxT("fill-opacity:0.0; ");
98 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
104 } // anonymous namespace
106 // ----------------------------------------------------------
108 // ----------------------------------------------------------
110 IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl
, wxDC
)
112 wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC
*owner
, const wxString
&filename
,
113 int width
, int height
, double dpi
) :
116 Init( filename
, width
, height
, dpi
);
119 void wxSVGFileDCImpl::Init (const wxString
&filename
, int Width
, int Height
, double dpi
)
128 m_mm_to_pix_x
= dpi
/25.4;
129 m_mm_to_pix_y
= dpi
/25.4;
131 m_backgroundBrush
= *wxTRANSPARENT_BRUSH
;
132 m_textForegroundColour
= *wxBLACK
;
133 m_textBackgroundColour
= *wxWHITE
;
134 m_colour
= wxColourDisplay();
136 m_pen
= *wxBLACK_PEN
;
137 m_font
= *wxNORMAL_FONT
;
138 m_brush
= *wxWHITE_BRUSH
;
140 m_graphics_changed
= true;
142 ////////////////////code here
144 m_outfile
= new wxFileOutputStream(filename
);
145 m_OK
= m_outfile
->Ok ();
148 m_filename
= filename
;
151 s
= wxT("<?xml version=\"1.0\" standalone=\"no\"?>") + wxString(wxT("\n"));
153 s
= wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + wxString(wxT("\n"));
155 s
= wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + wxString(wxT("\n"));
157 s
= wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + wxString(wxT("\n"));
159 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
);
161 s
= wxT("<title>SVG Picture created as ") + wxFileName(filename
).GetFullName() + wxT(" </title>") + wxT("\n");
163 s
= wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion
+ wxT(" </desc>")+ wxT("\n");
165 s
= wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + wxString(wxT("\n"));
170 wxSVGFileDCImpl::~wxSVGFileDCImpl()
172 wxString s
= wxT("</g> \n</svg> \n");
177 void wxSVGFileDCImpl::DoGetSizeMM( int *width
, int *height
) const
180 *width
= wxRound( (double)m_width
/ m_mm_to_pix_x
);
183 *height
= wxRound( (double)m_height
/ m_mm_to_pix_y
);
186 wxSize
wxSVGFileDCImpl::GetPPI() const
188 return wxSize( wxRound(m_dpi
), wxRound(m_dpi
) );
191 void wxSVGFileDCImpl::DoDrawLine (wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
193 if (m_graphics_changed
) NewGraphics ();
195 s
.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1
,y1
,x2
,y2
);
200 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawLine Call executed"));
201 CalcBoundingBox(x1
, y1
);
202 CalcBoundingBox(x2
, y2
);
206 void wxSVGFileDCImpl::DoDrawLines(int n
, wxPoint points
[], wxCoord xoffset
, wxCoord yoffset
)
208 for ( int i
= 1; i
< n
; i
++ )
210 DoDrawLine ( points
[i
-1].x
+ xoffset
, points
[i
-1].y
+ yoffset
,
211 points
[ i
].x
+ xoffset
, points
[ i
].y
+ yoffset
);
215 void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1
, wxCoord y1
)
218 if (m_graphics_changed
) NewGraphics ();
219 s
= wxT("<g style = \"stroke-linecap:round;\" > ") + wxString(wxT("\n"));
221 DoDrawLine ( x1
,y1
,x1
,y1
);
226 void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1
, wxCoord y1
, wxCoord width
, wxCoord height
)
228 wxDCImpl::DoDrawCheckMark (x1
,y1
,width
,height
);
231 void wxSVGFileDCImpl::DoDrawText(const wxString
& text
, wxCoord x1
, wxCoord y1
)
233 DoDrawRotatedText(text
, x1
,y1
,0.0);
234 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawText Call executed"));
237 void wxSVGFileDCImpl::DoDrawRotatedText(const wxString
& sText
, wxCoord x
, wxCoord y
, double angle
)
239 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
240 if (m_graphics_changed
) NewGraphics ();
243 // calculate bounding box
245 DoGetTextExtent(sText
, &w
, &h
, &desc
);
247 double rad
= DegToRad(angle
);
249 // wxT("upper left") and wxT("upper right")
250 CalcBoundingBox(x
, y
);
251 CalcBoundingBox((wxCoord
)(x
+ w
*cos(rad
)), (wxCoord
)(y
- h
*sin(rad
)));
253 // wxT("bottom left") and wxT("bottom right")
254 x
+= (wxCoord
)(h
*sin(rad
));
255 y
+= (wxCoord
)(h
*cos(rad
));
256 CalcBoundingBox(x
, y
);
257 CalcBoundingBox((wxCoord
)(x
+ h
*sin(rad
)), (wxCoord
)(y
+ h
*cos(rad
)));
259 if (m_backgroundMode
== wxBRUSHSTYLE_SOLID
)
261 // draw background first
262 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
264 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::Draw Rotated Text Call plotting text background"));
265 sTmp
.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x
,y
+desc
-h
, w
, h
);
266 s
= sTmp
+ wxT("style=\"") + wxBrushString(m_textBackgroundColour
);
267 s
+= wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour
);
268 sTmp
.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle
), x
,y
);
269 s
+= sTmp
+ wxT("\n");
272 //now do the text itself
273 s
.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x
,y
);
275 sTmp
= m_font
.GetFaceName ();
276 if (sTmp
.Len () > 0) s
+= wxT("style=\"font-family:") + sTmp
+ wxT("; ");
277 else s
+= wxT("style=\" ");
279 wxString fontweights
[3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
280 s
+= wxT("font-weight:") + fontweights
[m_font
.GetWeight() - wxNORMAL
] + wxT("; ");
282 wxString fontstyles
[5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
283 s
+= wxT("font-style:") + fontstyles
[m_font
.GetStyle() - wxNORMAL
] + wxT("; ");
285 sTmp
.Printf (wxT("font-size:%dpt; "), m_font
.GetPointSize () );
287 //text will be solid, unless alpha value isn't opaque in the foreground colour
288 s
+= wxBrushString(m_textForegroundColour
) + wxPenString(m_textForegroundColour
);
289 sTmp
.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle
), x
,y
);
290 s
+= sTmp
+ sText
+ wxT("</text> ") + wxT("\n");
295 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DrawRotatedText Call executed"));
298 void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
300 DoDrawRoundedRectangle(x
, y
, width
, height
, 0);
303 void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
, double radius
)
306 if (m_graphics_changed
) NewGraphics ();
309 s
.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
310 x
, y
, width
, height
, NumStr(radius
) );
315 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawRoundedRectangle Call executed"));
316 CalcBoundingBox(x
, y
);
317 CalcBoundingBox(x
+ width
, y
+ height
);
320 void wxSVGFileDCImpl::DoDrawPolygon(int n
, wxPoint points
[],
321 wxCoord xoffset
, wxCoord yoffset
,
322 wxPolygonFillMode fillStyle
)
324 if (m_graphics_changed
) NewGraphics ();
326 s
= wxT("<polygon style=\"");
327 if ( fillStyle
== wxODDEVEN_RULE
)
328 s
+= wxT("fill-rule:evenodd; ");
330 s
+= wxT("fill-rule:nonzero; ");
332 s
+= wxT("\" \npoints=\"");
334 for (int i
= 0; i
< n
; i
++)
336 sTmp
.Printf ( wxT("%d,%d"), points
[i
].x
+xoffset
, points
[i
].y
+yoffset
);
337 s
+= sTmp
+ wxT("\n");
338 CalcBoundingBox ( points
[i
].x
+xoffset
, points
[i
].y
+yoffset
);
340 s
+= wxT("\" /> \n");
343 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawPolygon Call executed"));
346 void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
349 if (m_graphics_changed
) NewGraphics ();
355 s
.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x
+rw
,y
+rh
, rw
, rh
);
360 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawEllipse Call executed"));
361 CalcBoundingBox(x
, y
);
362 CalcBoundingBox(x
+ width
, y
+ height
);
365 void wxSVGFileDCImpl::DoDrawArc(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
, wxCoord xc
, wxCoord yc
)
367 /* Draws an arc of a circle, centred on (xc, yc), with starting point
368 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
369 and the current brush for filling the shape.
371 The arc is drawn in an anticlockwise direction from the start point to
374 Might be better described as Pie drawing */
376 if (m_graphics_changed
) NewGraphics ();
379 // we need the radius of the circle which has two estimates
380 double r1
= sqrt ( double( (x1
-xc
)*(x1
-xc
) ) + double( (y1
-yc
)*(y1
-yc
) ) );
381 double r2
= sqrt ( double( (x2
-xc
)*(x2
-xc
) ) + double( (y2
-yc
)*(y2
-yc
) ) );
383 wxASSERT_MSG( (fabs ( r2
-r1
) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
384 if ( fabs ( r2
-r1
) > 3 ) //pixels
386 s
= wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
390 double theta1
= atan2((double)(yc
-y1
),(double)(x1
-xc
));
391 if ( theta1
< 0 ) theta1
= theta1
+ M_PI
* 2;
392 double theta2
= atan2((double)(yc
-y2
), (double)(x2
-xc
));
393 if ( theta2
< 0 ) theta2
= theta2
+ M_PI
* 2;
394 if ( theta2
< theta1
) theta2
= theta2
+ M_PI
*2;
396 int fArc
; // flag for large or small arc 0 means less than 180 degrees
397 if ( fabs(theta2
- theta1
) > M_PI
) fArc
= 1; else fArc
= 0;
399 int fSweep
= 0; // flag for sweep always 0
401 s
.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
402 x1
,y1
, NumStr(r1
), NumStr(r2
), fArc
, fSweep
, x2
, y2
, xc
, yc
);
404 // the z means close the path and fill
405 s
+= wxT(" \" /> \n");
413 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawArc Call executed"));
416 void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x
,wxCoord y
,wxCoord w
,wxCoord h
,double sa
,double ea
)
419 Draws an arc of an ellipse. The current pen is used for drawing the arc
420 and the current brush is used for drawing the pie. This function is
421 currently only available for X window and PostScript device contexts.
423 x and y specify the x and y coordinates of the upper-left corner of the
424 rectangle that contains the ellipse.
426 width and height specify the width and height of the rectangle that
427 contains the ellipse.
429 start and end specify the start and end of the arc relative to the
430 three-o'clock position from the center of the rectangle. Angles are
431 specified in degrees (360 is a complete circle). Positive values mean
432 counter-clockwise motion. If start is equal to end, a complete ellipse
435 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
437 if (m_graphics_changed
) NewGraphics ();
447 double xs
, ys
, xe
, ye
;
448 xs
= xc
+ rx
* cos (DegToRad(sa
));
449 xe
= xc
+ rx
* cos (DegToRad(ea
));
450 ys
= yc
- ry
* sin (DegToRad(sa
));
451 ye
= yc
- ry
* sin (DegToRad(ea
));
453 ///now same as circle arc...
455 double theta1
= atan2(ys
-yc
, xs
-xc
);
456 double theta2
= atan2(ye
-yc
, xe
-xc
);
458 int fArc
; // flag for large or small arc 0 means less than 180 degrees
459 if ( (theta2
- theta1
) > 0 ) fArc
= 1; else fArc
= 0;
462 if ( fabs(theta2
- theta1
) > M_PI
) fSweep
= 1; else fSweep
= 0;
464 s
.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
465 int(xs
), int(ys
), int(rx
), int(ry
),
466 fArc
, fSweep
, int(xe
), int(ye
), int(xc
), int(yc
) );
468 s
+= wxT(" \" /> \n");
475 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawEllipticArc Call executed"));
478 void wxSVGFileDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*w
, wxCoord
*h
, wxCoord
*descent
, wxCoord
*externalLeading
, const wxFont
*font
) const
483 sDC
.SetFont (m_font
);
484 if ( font
!= NULL
) sDC
.SetFont ( *font
);
485 sDC
.GetTextExtent(string
, w
, h
, descent
, externalLeading
);
486 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetTextExtent Call executed"));
489 wxCoord
wxSVGFileDCImpl::GetCharHeight() const
493 sDC
.SetFont (m_font
);
495 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetCharHeight Call executing"));
496 return ( sDC
.GetCharHeight() );
500 wxCoord
wxSVGFileDCImpl::GetCharWidth() const
503 sDC
.SetFont (m_font
);
505 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::GetCharWidth Call executing"));
506 return ( sDC
.GetCharWidth() );
511 // ----------------------------------------------------------
512 // wxSVGFileDCImpl - set functions
513 // ----------------------------------------------------------
515 void wxSVGFileDCImpl::SetBackground( const wxBrush
&brush
)
518 m_backgroundBrush
= brush
;
523 void wxSVGFileDCImpl::SetBackgroundMode( int mode
)
525 m_backgroundMode
= mode
;
530 void wxSVGFileDCImpl::SetBrush(const wxBrush
& brush
)
535 m_graphics_changed
= true;
536 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetBrush Call executed"));
540 void wxSVGFileDCImpl::SetPen(const wxPen
& pen
)
542 // width, color, ends, joins : currently implemented
543 // dashes, stipple : not implemented
546 m_graphics_changed
= true;
547 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetPen Call executed"));
550 void wxSVGFileDCImpl::NewGraphics ()
552 wxString s
, sBrush
, sPenCap
, sPenJoin
, sPenStyle
, sLast
, sWarn
;
554 sBrush
= wxT("</g>\n<g style=\"") + wxBrushString ( m_brush
.GetColour (), m_brush
.GetStyle () )
555 + wxPenString(m_pen
.GetColour(), m_pen
.GetStyle());
557 switch ( m_pen
.GetCap () )
559 case wxCAP_PROJECTING
:
560 sPenCap
= wxT("stroke-linecap:square; ");
563 sPenCap
= wxT("stroke-linecap:butt; ");
567 sPenCap
= wxT("stroke-linecap:round; ");
569 switch ( m_pen
.GetJoin () )
572 sPenJoin
= wxT("stroke-linejoin:bevel; ");
575 sPenJoin
= wxT("stroke-linejoin:miter; ");
579 sPenJoin
= wxT("stroke-linejoin:round; ");
582 sLast
.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
583 m_pen
.GetWidth(), NumStr(m_logicalOriginX
), NumStr(m_logicalOriginY
), NumStr(m_scaleX
), NumStr(m_scaleY
) );
585 s
= sBrush
+ sPenCap
+ sPenJoin
+ sPenStyle
+ sLast
+ wxT("\n") + sWarn
;
587 m_graphics_changed
= false;
588 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::NewGraphics Call executed"));
592 void wxSVGFileDCImpl::SetFont(const wxFont
& font
)
597 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::SetFont Call executed"));
600 // export a bitmap as a raster image in png
601 bool wxSVGFileDCImpl::DoBlit(wxCoord xdest
, wxCoord ydest
, wxCoord width
, wxCoord height
,
602 wxDC
* source
, wxCoord xsrc
, wxCoord ysrc
,
603 wxRasterOperationMode logicalFunc
/*= wxCOPY*/, bool useMask
/*= false*/,
604 wxCoord
/*xsrcMask = -1*/, wxCoord
/*ysrcMask = -1*/)
606 if (logicalFunc
!= wxCOPY
)
608 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
611 if (useMask
!= false)
613 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
616 wxBitmap
myBitmap (width
, height
);
618 memDC
.SelectObject( myBitmap
);
619 memDC
.Blit(0, 0, width
, height
, source
, xsrc
, ysrc
);
620 memDC
.SelectObject( wxNullBitmap
);
621 DoDrawBitmap(myBitmap
, xdest
, ydest
);
622 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoBlit Call executed"));
626 void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon
& myIcon
, wxCoord x
, wxCoord y
)
628 wxBitmap
myBitmap (myIcon
.GetWidth(), myIcon
.GetHeight() );
630 memDC
.SelectObject( myBitmap
);
631 memDC
.DrawIcon(myIcon
,0,0);
632 memDC
.SelectObject( wxNullBitmap
);
633 DoDrawBitmap(myBitmap
, x
, y
);
634 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawIcon Call executed"));
638 void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap
& bmp
, wxCoord x
, wxCoord y
, bool WXUNUSED(bTransparent
) /*=0*/ )
640 if (m_graphics_changed
) NewGraphics ();
642 wxString sTmp
, s
, sPNG
;
643 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG
) == NULL
)
644 wxImage::AddHandler(new wxPNGHandler
);
646 // create suitable file name
647 sTmp
.Printf ( wxT("_image%d.png"), m_sub_images
);
648 sPNG
= m_filename
.BeforeLast(wxT('.')) + sTmp
;
649 while (wxFile::Exists(sPNG
) )
652 sTmp
.Printf ( wxT("_image%d.png"), m_sub_images
);
653 sPNG
= m_filename
.BeforeLast(wxT('.')) + sTmp
;
656 //create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
657 wxBitmap myBitmap
= bmp
;
659 bool bPNG_OK
= myBitmap
.SaveFile(sPNG
,wxBITMAP_TYPE_PNG
);
661 // reference the bitmap from the SVG doc
662 // only use filename & ext
663 sPNG
= sPNG
.AfterLast(wxFileName::GetPathSeparator());
665 // reference the bitmap from the SVG doc
666 int w
= myBitmap
.GetWidth();
667 int h
= myBitmap
.GetHeight();
668 sTmp
.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x
,y
,w
,h
);
670 sTmp
.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG
.c_str() );
671 s
+= sTmp
+ wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
677 m_OK
= m_outfile
->Ok () && bPNG_OK
;
678 wxASSERT_MSG(!wxSVG_DEBUG
, wxT("wxSVGFileDC::DoDrawBitmap Call executed"));
683 void wxSVGFileDCImpl::write(const wxString
&s
)
685 const wxCharBuffer buf
= s
.utf8_str();
686 m_outfile
->Write(buf
, strlen((const char *)buf
));
687 m_OK
= m_outfile
->Ok();