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