]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcsvg.cpp
fix memory leak in wxScreenDC, fixes #13249
[wxWidgets.git] / src / common / dcsvg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/svg.cpp
3 // Purpose: SVG sample
4 // Author: Chris Elliott
5 // Modified by:
6 // RCS-ID: $Id$
7 // Licence: wxWindows licence
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 #if wxUSE_SVG
19
20 #ifndef WX_PRECOMP
21 #include "wx/dcmemory.h"
22 #include "wx/dcscreen.h"
23 #include "wx/icon.h"
24 #include "wx/image.h"
25 #endif
26
27 #include "wx/dcsvg.h"
28 #include "wx/wfstream.h"
29 #include "wx/filename.h"
30
31 // ----------------------------------------------------------
32 // Global utilities
33 // ----------------------------------------------------------
34
35 namespace
36 {
37
38 inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
39
40 // This function returns a string representation of a floating point number in
41 // C locale (i.e. always using "." for the decimal separator) and with the
42 // fixed precision (which is 2 for some unknown reason but this is what it was
43 // in this code originally).
44 inline wxString NumStr(double f)
45 {
46 return wxString::FromCDouble(f, 2);
47 }
48
49 wxString wxPenString(wxColour c, int style = wxPENSTYLE_SOLID)
50 {
51 wxString s = wxT("stroke:") + c.GetAsString(wxC2S_HTML_SYNTAX) + wxT("; ");
52 // Use the color's alpha value (if not opaque) for the opacity.
53 // Note that a transparent pen will override the alpha value.
54 if (c.Alpha() != wxALPHA_OPAQUE && style != wxPENSTYLE_TRANSPARENT)
55 {
56 s += wxString::Format(wxT("stroke-opacity:%s; "), NumStr(c.Alpha()/255.));
57 }
58 else
59 {
60 switch ( style )
61 {
62 case wxPENSTYLE_SOLID:
63 s += wxT("stroke-opacity:1.0; ");
64 break;
65 case wxPENSTYLE_TRANSPARENT:
66 s += wxT("stroke-opacity:0.0; ");
67 break;
68 default :
69 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Pen Style not available"));
70 }
71 }
72 return s;
73 }
74
75 wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
76 {
77 wxString s = wxT("fill:") + c.GetAsString(wxC2S_HTML_SYNTAX) + wxT("; ");
78 // Use the color's alpha value (if not opaque) for the opacity.
79 // Note that a transparent brush will override the alpha value.
80 if (c.Alpha() != wxALPHA_OPAQUE && style != wxBRUSHSTYLE_TRANSPARENT)
81 {
82 s += wxString::Format(wxT("fill-opacity:%s; "), NumStr(c.Alpha()/255.));
83 }
84 else
85 {
86 switch ( style )
87 {
88 case wxBRUSHSTYLE_SOLID:
89 s += wxT("fill-opacity:1.0; ");
90 break;
91 case wxBRUSHSTYLE_TRANSPARENT:
92 s += wxT("fill-opacity:0.0; ");
93 break;
94 default :
95 wxASSERT_MSG(false, wxT("wxSVGFileDC::Requested Brush Style not available"));
96 }
97 }
98 return s;
99 }
100
101 } // anonymous namespace
102
103 // ----------------------------------------------------------
104 // wxSVGFileDCImpl
105 // ----------------------------------------------------------
106
107 IMPLEMENT_ABSTRACT_CLASS(wxSVGFileDCImpl, wxDC)
108
109 wxSVGFileDCImpl::wxSVGFileDCImpl( wxSVGFileDC *owner, const wxString &filename,
110 int width, int height, double dpi ) :
111 wxDCImpl( owner )
112 {
113 Init( filename, width, height, dpi );
114 }
115
116 void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, double dpi)
117 {
118 m_width = Width;
119 m_height = Height;
120
121 m_dpi = dpi;
122
123 m_OK = true;
124
125 m_mm_to_pix_x = dpi/25.4;
126 m_mm_to_pix_y = dpi/25.4;
127
128 m_backgroundBrush = *wxTRANSPARENT_BRUSH;
129 m_textForegroundColour = *wxBLACK;
130 m_textBackgroundColour = *wxWHITE;
131 m_colour = wxColourDisplay();
132
133 m_pen = *wxBLACK_PEN;
134 m_font = *wxNORMAL_FONT;
135 m_brush = *wxWHITE_BRUSH;
136
137 m_graphics_changed = true;
138
139 ////////////////////code here
140
141 m_outfile = new wxFileOutputStream(filename);
142 m_OK = m_outfile->IsOk();
143 if (m_OK)
144 {
145 m_filename = filename;
146 m_sub_images = 0;
147 wxString s;
148 s = wxT("<?xml version=\"1.0\" standalone=\"no\"?>") + wxString(wxT("\n"));
149 write(s);
150 s = wxT("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" ") + wxString(wxT("\n"));
151 write(s);
152 s = wxT("\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"> ") + wxString(wxT("\n"));
153 write(s);
154 s = wxT("<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ") + wxString(wxT("\n"));
155 write(s);
156 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 );
157 write(s);
158 s = wxT("<title>SVG Picture created as ") + wxFileName(filename).GetFullName() + wxT(" </title>") + wxT("\n");
159 write(s);
160 s = wxString (wxT("<desc>Picture generated by wxSVG ")) + wxSVGVersion + wxT(" </desc>")+ wxT("\n");
161 write(s);
162 s = wxT("<g style=\"fill:black; stroke:black; stroke-width:1\">") + wxString(wxT("\n"));
163 write(s);
164 }
165 }
166
167 wxSVGFileDCImpl::~wxSVGFileDCImpl()
168 {
169 wxString s = wxT("</g> \n</svg> \n");
170 write(s);
171 delete m_outfile;
172 }
173
174 void wxSVGFileDCImpl::DoGetSizeMM( int *width, int *height ) const
175 {
176 if (width)
177 *width = wxRound( (double)m_width / m_mm_to_pix_x );
178
179 if (height)
180 *height = wxRound( (double)m_height / m_mm_to_pix_y );
181 }
182
183 wxSize wxSVGFileDCImpl::GetPPI() const
184 {
185 return wxSize( wxRound(m_dpi), wxRound(m_dpi) );
186 }
187
188 void wxSVGFileDCImpl::DoDrawLine (wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
189 {
190 if (m_graphics_changed) NewGraphics();
191 wxString s;
192 s.Printf ( wxT("<path d=\"M%d %d L%d %d\" /> \n"), x1,y1,x2,y2 );
193 if (m_OK)
194 {
195 write(s);
196 }
197 CalcBoundingBox(x1, y1);
198 CalcBoundingBox(x2, y2);
199 }
200
201 void wxSVGFileDCImpl::DoDrawLines(int n, wxPoint points[], wxCoord xoffset , wxCoord yoffset )
202 {
203 for ( int i = 1; i < n; i++ )
204 {
205 DoDrawLine ( points [i-1].x + xoffset, points [i-1].y + yoffset,
206 points [ i ].x + xoffset, points [ i ].y + yoffset );
207 }
208 }
209
210 void wxSVGFileDCImpl::DoDrawPoint (wxCoord x1, wxCoord y1)
211 {
212 wxString s;
213 if (m_graphics_changed) NewGraphics();
214 s = wxT("<g style = \"stroke-linecap:round;\" > ") + wxString(wxT("\n"));
215 write(s);
216 DoDrawLine ( x1,y1,x1,y1 );
217 s = wxT("</g>");
218 write(s);
219 }
220
221 void wxSVGFileDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height)
222 {
223 wxDCImpl::DoDrawCheckMark (x1,y1,width,height);
224 }
225
226 void wxSVGFileDCImpl::DoDrawText(const wxString& text, wxCoord x1, wxCoord y1)
227 {
228 DoDrawRotatedText(text, x1,y1,0.0);
229 }
230
231 void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoord y, double angle)
232 {
233 //known bug; if the font is drawn in a scaled DC, it will not behave exactly as wxMSW
234 if (m_graphics_changed) NewGraphics();
235 wxString s, sTmp;
236
237 // calculate bounding box
238 wxCoord w, h, desc;
239 DoGetTextExtent(sText, &w, &h, &desc);
240
241 double rad = DegToRad(angle);
242
243 // wxT("upper left") and wxT("upper right")
244 CalcBoundingBox(x, y);
245 CalcBoundingBox((wxCoord)(x + w*cos(rad)), (wxCoord)(y - h*sin(rad)));
246
247 // wxT("bottom left") and wxT("bottom right")
248 x += (wxCoord)(h*sin(rad));
249 y += (wxCoord)(h*cos(rad));
250 CalcBoundingBox(x, y);
251 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
252
253 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
254 {
255 // draw background first
256 // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
257
258 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x,y+desc-h, w, h );
259 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
260 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
261 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
262 s += sTmp + wxT("\n");
263 write(s);
264 }
265 //now do the text itself
266 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
267
268 sTmp = m_font.GetFaceName();
269 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
270 else s += wxT("style=\" ");
271
272 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
273 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
274
275 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
276 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
277
278 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
279 s += sTmp;
280 //text will be solid, unless alpha value isn't opaque in the foreground colour
281 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
282 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
283 s += sTmp + sText + wxT("</text> ") + wxT("\n");
284 if (m_OK)
285 {
286 write(s);
287 }
288 }
289
290 void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
291 {
292 DoDrawRoundedRectangle(x, y, width, height, 0);
293 }
294
295 void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
296
297 {
298 if (m_graphics_changed) NewGraphics();
299 wxString s;
300
301 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
302 x, y, width, height, NumStr(radius) );
303
304 s += wxT(" /> \n");
305 write(s);
306
307 CalcBoundingBox(x, y);
308 CalcBoundingBox(x + width, y + height);
309 }
310
311 void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
312 wxCoord xoffset, wxCoord yoffset,
313 wxPolygonFillMode fillStyle)
314 {
315 if (m_graphics_changed) NewGraphics();
316 wxString s, sTmp;
317 s = wxT("<polygon style=\"");
318 if ( fillStyle == wxODDEVEN_RULE )
319 s += wxT("fill-rule:evenodd; ");
320 else
321 s += wxT("fill-rule:nonzero; ");
322
323 s += wxT("\" \npoints=\"");
324
325 for (int i = 0; i < n; i++)
326 {
327 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
328 s += sTmp + wxT("\n");
329 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
330 }
331 s += wxT("\" /> \n");
332 write(s);
333 }
334
335 void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
336
337 {
338 if (m_graphics_changed) NewGraphics();
339
340 int rh = height /2;
341 int rw = width /2;
342
343 wxString s;
344 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
345 s += wxT(" /> \n");
346
347 write(s);
348
349 CalcBoundingBox(x, y);
350 CalcBoundingBox(x + width, y + height);
351 }
352
353 void wxSVGFileDCImpl::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%s %s 0.0 %d %d %d %d L%d %d z "),
390 x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
391
392 // the z means close the path and fill
393 s += wxT(" \" /> \n");
394
395
396 if (m_OK)
397 {
398 write(s);
399 }
400 }
401
402 void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
403 {
404 /*
405 Draws an arc of an ellipse. The current pen is used for drawing the arc
406 and the current brush is used for drawing the pie. This function is
407 currently only available for X window and PostScript device contexts.
408
409 x and y specify the x and y coordinates of the upper-left corner of the
410 rectangle that contains the ellipse.
411
412 width and height specify the width and height of the rectangle that
413 contains the ellipse.
414
415 start and end specify the start and end of the arc relative to the
416 three-o'clock position from the center of the rectangle. Angles are
417 specified in degrees (360 is a complete circle). Positive values mean
418 counter-clockwise motion. If start is equal to end, a complete ellipse
419 will be drawn. */
420
421 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
422
423 if (m_graphics_changed) NewGraphics();
424
425 wxString s;
426 //radius
427 double rx = w / 2;
428 double ry = h / 2;
429 // center
430 double xc = x + rx;
431 double yc = y + ry;
432
433 double xs, ys, xe, ye;
434 xs = xc + rx * cos (DegToRad(sa));
435 xe = xc + rx * cos (DegToRad(ea));
436 ys = yc - ry * sin (DegToRad(sa));
437 ye = yc - ry * sin (DegToRad(ea));
438
439 ///now same as circle arc...
440
441 double theta1 = atan2(ys-yc, xs-xc);
442 double theta2 = atan2(ye-yc, xe-xc);
443
444 int fArc; // flag for large or small arc 0 means less than 180 degrees
445 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
446
447 int fSweep;
448 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
449
450 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
451 int(xs), int(ys), int(rx), int(ry),
452 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
453
454 s += wxT(" \" /> \n");
455
456 if (m_OK)
457 {
458 write(s);
459 }
460 }
461
462 void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
463
464 {
465 wxScreenDC sDC;
466
467 sDC.SetFont (m_font);
468 if ( font != NULL ) sDC.SetFont ( *font );
469 sDC.GetTextExtent(string, w, h, descent, externalLeading );
470 }
471
472 wxCoord wxSVGFileDCImpl::GetCharHeight() const
473 {
474 wxScreenDC sDC;
475 sDC.SetFont (m_font);
476
477 return sDC.GetCharHeight();
478
479 }
480
481 wxCoord wxSVGFileDCImpl::GetCharWidth() const
482 {
483 wxScreenDC sDC;
484 sDC.SetFont (m_font);
485
486 return sDC.GetCharWidth();
487 }
488
489
490 // ----------------------------------------------------------
491 // wxSVGFileDCImpl - set functions
492 // ----------------------------------------------------------
493
494 void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
495 {
496 m_backgroundBrush = brush;
497 }
498
499
500 void wxSVGFileDCImpl::SetBackgroundMode( int mode )
501 {
502 m_backgroundMode = mode;
503 }
504
505
506 void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
507
508 {
509 m_brush = brush;
510
511 m_graphics_changed = true;
512 }
513
514
515 void wxSVGFileDCImpl::SetPen(const wxPen& pen)
516 {
517 // width, color, ends, joins : currently implemented
518 // dashes, stipple : not implemented
519 m_pen = pen;
520
521 m_graphics_changed = true;
522 }
523
524 void wxSVGFileDCImpl::NewGraphics()
525 {
526 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
527
528 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
529 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
530
531 switch ( m_pen.GetCap() )
532 {
533 case wxCAP_PROJECTING :
534 sPenCap = wxT("stroke-linecap:square; ");
535 break;
536 case wxCAP_BUTT :
537 sPenCap = wxT("stroke-linecap:butt; ");
538 break;
539 case wxCAP_ROUND :
540 default :
541 sPenCap = wxT("stroke-linecap:round; ");
542 }
543
544 switch ( m_pen.GetJoin() )
545 {
546 case wxJOIN_BEVEL :
547 sPenJoin = wxT("stroke-linejoin:bevel; ");
548 break;
549 case wxJOIN_MITER :
550 sPenJoin = wxT("stroke-linejoin:miter; ");
551 break;
552 case wxJOIN_ROUND :
553 default :
554 sPenJoin = wxT("stroke-linejoin:round; ");
555 }
556
557 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
558 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
559
560 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n") + sWarn;
561 write(s);
562 m_graphics_changed = false;
563 }
564
565
566 void wxSVGFileDCImpl::SetFont(const wxFont& font)
567
568 {
569 m_font = font;
570 }
571
572 // export a bitmap as a raster image in png
573 bool wxSVGFileDCImpl::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
574 wxDC* source, wxCoord xsrc, wxCoord ysrc,
575 wxRasterOperationMode logicalFunc /*= wxCOPY*/, bool useMask /*= false*/,
576 wxCoord /*xsrcMask = -1*/, wxCoord /*ysrcMask = -1*/)
577 {
578 if (logicalFunc != wxCOPY)
579 {
580 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
581 return false;
582 }
583 if (useMask != false)
584 {
585 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
586 return false;
587 }
588 wxBitmap myBitmap (width, height);
589 wxMemoryDC memDC;
590 memDC.SelectObject( myBitmap );
591 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
592 memDC.SelectObject( wxNullBitmap );
593 DoDrawBitmap(myBitmap, xdest, ydest);
594 return false;
595 }
596
597 void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
598 {
599 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
600 wxMemoryDC memDC;
601 memDC.SelectObject( myBitmap );
602 memDC.DrawIcon(myIcon,0,0);
603 memDC.SelectObject( wxNullBitmap );
604 DoDrawBitmap(myBitmap, x, y);
605 }
606
607 void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
608 {
609 if (m_graphics_changed) NewGraphics();
610
611 wxString sTmp, s, sPNG;
612 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
613 wxImage::AddHandler(new wxPNGHandler);
614
615 // create suitable file name
616 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
617 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
618 while (wxFile::Exists(sPNG) )
619 {
620 m_sub_images ++;
621 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
622 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
623 }
624
625 //create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
626 wxBitmap myBitmap = bmp;
627 //save it
628 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
629
630 // reference the bitmap from the SVG doc
631 // only use filename & ext
632 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
633
634 // reference the bitmap from the SVG doc
635 int w = myBitmap.GetWidth();
636 int h = myBitmap.GetHeight();
637 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
638 s += sTmp;
639 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
640 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
641
642 if (m_OK && bPNG_OK)
643 {
644 write(s);
645 }
646 m_OK = m_outfile->IsOk() && bPNG_OK;
647 }
648
649 void wxSVGFileDCImpl::write(const wxString &s)
650 {
651 const wxCharBuffer buf = s.utf8_str();
652 m_outfile->Write(buf, strlen((const char *)buf));
653 m_OK = m_outfile->IsOk();
654 }
655
656
657 #ifdef __BORLANDC__
658 #pragma warn .rch
659 #pragma warn .ccc
660 #endif
661
662 #endif // wxUSE_SVG
663