]> git.saurik.com Git - wxWidgets.git/blob - src/common/dcsvg.cpp
Factor out text measurement from wxDC and wxWindow into wxTextMeasure.
[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 NewGraphicsIfNeeded();
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 NewGraphicsIfNeeded();
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 NewGraphicsIfNeeded();
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 CalcBoundingBox((wxCoord)(x + h*sin(rad)), (wxCoord)(y + h*cos(rad)));
257 CalcBoundingBox((wxCoord)(x + h*sin(rad) + w*cos(rad)), (wxCoord)(y + h*cos(rad) - w*sin(rad)));
258
259 if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
260 {
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
263
264 sTmp.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h );
265 s = sTmp + wxT("style=\"") + wxBrushString(m_textBackgroundColour);
266 s += wxT("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
267 sTmp.Printf ( wxT("\" transform=\"rotate( %s %d %d ) \" />"), NumStr(-angle), x,y );
268 s += sTmp + wxT("\n");
269 write(s);
270 }
271
272 // convert x,y to SVG text x,y (the coordinates of the text baseline)
273 x = (wxCoord)(x + (h-desc)*sin(rad));
274 y = (wxCoord)(y + (h-desc)*cos(rad));
275
276 //now do the text itself
277 s.Printf (wxT(" <text x=\"%d\" y=\"%d\" "),x,y );
278
279 sTmp = m_font.GetFaceName();
280 if (sTmp.Len() > 0) s += wxT("style=\"font-family:") + sTmp + wxT("; ");
281 else s += wxT("style=\" ");
282
283 wxString fontweights [3] = { wxT("normal"), wxT("lighter"), wxT("bold") };
284 s += wxT("font-weight:") + fontweights[m_font.GetWeight() - wxNORMAL] + wxT("; ");
285
286 wxString fontstyles [5] = { wxT("normal"), wxT("style error"), wxT("style error"), wxT("italic"), wxT("oblique") };
287 s += wxT("font-style:") + fontstyles[m_font.GetStyle() - wxNORMAL] + wxT("; ");
288
289 sTmp.Printf (wxT("font-size:%dpt; "), m_font.GetPointSize() );
290 s += sTmp;
291 //text will be solid, unless alpha value isn't opaque in the foreground colour
292 s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
293 sTmp.Printf ( wxT("stroke-width:0;\" transform=\"rotate( %s %d %d ) \" >"), NumStr(-angle), x,y );
294 s += sTmp + sText + wxT("</text> ") + wxT("\n");
295 if (m_OK)
296 {
297 write(s);
298 }
299 }
300
301 void wxSVGFileDCImpl::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
302 {
303 DoDrawRoundedRectangle(x, y, width, height, 0);
304 }
305
306 void wxSVGFileDCImpl::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius )
307
308 {
309 NewGraphicsIfNeeded();
310 wxString s;
311
312 s.Printf ( wxT(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%s\" "),
313 x, y, width, height, NumStr(radius) );
314
315 s += wxT(" /> \n");
316 write(s);
317
318 CalcBoundingBox(x, y);
319 CalcBoundingBox(x + width, y + height);
320 }
321
322 void wxSVGFileDCImpl::DoDrawPolygon(int n, wxPoint points[],
323 wxCoord xoffset, wxCoord yoffset,
324 wxPolygonFillMode fillStyle)
325 {
326 NewGraphicsIfNeeded();
327 wxString s, sTmp;
328 s = wxT("<polygon style=\"");
329 if ( fillStyle == wxODDEVEN_RULE )
330 s += wxT("fill-rule:evenodd; ");
331 else
332 s += wxT("fill-rule:nonzero; ");
333
334 s += wxT("\" \npoints=\"");
335
336 for (int i = 0; i < n; i++)
337 {
338 sTmp.Printf ( wxT("%d,%d"), points [i].x+xoffset, points[i].y+yoffset );
339 s += sTmp + wxT("\n");
340 CalcBoundingBox ( points [i].x+xoffset, points[i].y+yoffset);
341 }
342 s += wxT("\" /> \n");
343 write(s);
344 }
345
346 void wxSVGFileDCImpl::DoDrawEllipse (wxCoord x, wxCoord y, wxCoord width, wxCoord height)
347
348 {
349 NewGraphicsIfNeeded();
350
351 int rh = height /2;
352 int rw = width /2;
353
354 wxString s;
355 s.Printf ( wxT("<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" "), x+rw,y+rh, rw, rh );
356 s += wxT(" /> \n");
357
358 write(s);
359
360 CalcBoundingBox(x, y);
361 CalcBoundingBox(x + width, y + height);
362 }
363
364 void wxSVGFileDCImpl::DoDrawArc(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc)
365 {
366 /* Draws an arc of a circle, centred on (xc, yc), with starting point
367 (x1, y1) and ending at (x2, y2). The current pen is used for the outline
368 and the current brush for filling the shape.
369
370 The arc is drawn in an anticlockwise direction from the start point to
371 the end point.
372
373 Might be better described as Pie drawing */
374
375 NewGraphicsIfNeeded();
376 wxString s;
377
378 // we need the radius of the circle which has two estimates
379 double r1 = sqrt ( double( (x1-xc)*(x1-xc) ) + double( (y1-yc)*(y1-yc) ) );
380 double r2 = sqrt ( double( (x2-xc)*(x2-xc) ) + double( (y2-yc)*(y2-yc) ) );
381
382 wxASSERT_MSG( (fabs ( r2-r1 ) <= 3), wxT("wxSVGFileDC::DoDrawArc Error in getting radii of circle"));
383 if ( fabs ( r2-r1 ) > 3 ) //pixels
384 {
385 s = wxT("<!--- wxSVGFileDC::DoDrawArc Error in getting radii of circle --> \n");
386 write(s);
387 }
388
389 double theta1 = atan2((double)(yc-y1),(double)(x1-xc));
390 if ( theta1 < 0 ) theta1 = theta1 + M_PI * 2;
391 double theta2 = atan2((double)(yc-y2), (double)(x2-xc));
392 if ( theta2 < 0 ) theta2 = theta2 + M_PI * 2;
393 if ( theta2 < theta1 ) theta2 = theta2 + M_PI *2;
394
395 int fArc; // flag for large or small arc 0 means less than 180 degrees
396 if ( fabs(theta2 - theta1) > M_PI ) fArc = 1; else fArc = 0;
397
398 int fSweep = 0; // flag for sweep always 0
399
400 s.Printf ( wxT("<path d=\"M%d %d A%s %s 0.0 %d %d %d %d L%d %d z "),
401 x1,y1, NumStr(r1), NumStr(r2), fArc, fSweep, x2, y2, xc, yc );
402
403 // the z means close the path and fill
404 s += wxT(" \" /> \n");
405
406
407 if (m_OK)
408 {
409 write(s);
410 }
411 }
412
413 void wxSVGFileDCImpl::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
414 {
415 /*
416 Draws an arc of an ellipse. The current pen is used for drawing the arc
417 and the current brush is used for drawing the pie. This function is
418 currently only available for X window and PostScript device contexts.
419
420 x and y specify the x and y coordinates of the upper-left corner of the
421 rectangle that contains the ellipse.
422
423 width and height specify the width and height of the rectangle that
424 contains the ellipse.
425
426 start and end specify the start and end of the arc relative to the
427 three-o'clock position from the center of the rectangle. Angles are
428 specified in degrees (360 is a complete circle). Positive values mean
429 counter-clockwise motion. If start is equal to end, a complete ellipse
430 will be drawn. */
431
432 //known bug: SVG draws with the current pen along the radii, but this does not happen in wxMSW
433
434 NewGraphicsIfNeeded();
435
436 wxString s;
437 //radius
438 double rx = w / 2;
439 double ry = h / 2;
440 // center
441 double xc = x + rx;
442 double yc = y + ry;
443
444 double xs, ys, xe, ye;
445 xs = xc + rx * cos (DegToRad(sa));
446 xe = xc + rx * cos (DegToRad(ea));
447 ys = yc - ry * sin (DegToRad(sa));
448 ye = yc - ry * sin (DegToRad(ea));
449
450 ///now same as circle arc...
451
452 double theta1 = atan2(ys-yc, xs-xc);
453 double theta2 = atan2(ye-yc, xe-xc);
454
455 int fArc; // flag for large or small arc 0 means less than 180 degrees
456 if ( (theta2 - theta1) > 0 ) fArc = 1; else fArc = 0;
457
458 int fSweep;
459 if ( fabs(theta2 - theta1) > M_PI) fSweep = 1; else fSweep = 0;
460
461 s.Printf ( wxT("<path d=\"M%d %d A%d %d 0.0 %d %d %d %d L %d %d z "),
462 int(xs), int(ys), int(rx), int(ry),
463 fArc, fSweep, int(xe), int(ye), int(xc), int(yc) );
464
465 s += wxT(" \" /> \n");
466
467 if (m_OK)
468 {
469 write(s);
470 }
471 }
472
473 void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent , wxCoord *externalLeading , const wxFont *font) const
474
475 {
476 wxScreenDC sDC;
477
478 sDC.SetFont (m_font);
479 if ( font != NULL ) sDC.SetFont ( *font );
480 sDC.GetTextExtent(string, w, h, descent, externalLeading );
481 }
482
483 wxCoord wxSVGFileDCImpl::GetCharHeight() const
484 {
485 wxScreenDC sDC;
486 sDC.SetFont (m_font);
487
488 return sDC.GetCharHeight();
489
490 }
491
492 wxCoord wxSVGFileDCImpl::GetCharWidth() const
493 {
494 wxScreenDC sDC;
495 sDC.SetFont (m_font);
496
497 return sDC.GetCharWidth();
498 }
499
500
501 // ----------------------------------------------------------
502 // wxSVGFileDCImpl - set functions
503 // ----------------------------------------------------------
504
505 void wxSVGFileDCImpl::SetBackground( const wxBrush &brush )
506 {
507 m_backgroundBrush = brush;
508 }
509
510
511 void wxSVGFileDCImpl::SetBackgroundMode( int mode )
512 {
513 m_backgroundMode = mode;
514 }
515
516
517 void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
518 {
519 m_brush = brush;
520
521 m_graphics_changed = true;
522 }
523
524
525 void wxSVGFileDCImpl::SetPen(const wxPen& pen)
526 {
527 // width, color, ends, joins : currently implemented
528 // dashes, stipple : not implemented
529 m_pen = pen;
530
531 m_graphics_changed = true;
532 }
533
534 void wxSVGFileDCImpl::NewGraphicsIfNeeded()
535 {
536 if ( !m_graphics_changed )
537 return;
538
539 m_graphics_changed = false;
540
541 wxString s, sBrush, sPenCap, sPenJoin, sPenStyle, sLast, sWarn;
542
543 sBrush = wxT("</g>\n<g style=\"") + wxBrushString ( m_brush.GetColour(), m_brush.GetStyle() )
544 + wxPenString(m_pen.GetColour(), m_pen.GetStyle());
545
546 switch ( m_pen.GetCap() )
547 {
548 case wxCAP_PROJECTING :
549 sPenCap = wxT("stroke-linecap:square; ");
550 break;
551 case wxCAP_BUTT :
552 sPenCap = wxT("stroke-linecap:butt; ");
553 break;
554 case wxCAP_ROUND :
555 default :
556 sPenCap = wxT("stroke-linecap:round; ");
557 }
558
559 switch ( m_pen.GetJoin() )
560 {
561 case wxJOIN_BEVEL :
562 sPenJoin = wxT("stroke-linejoin:bevel; ");
563 break;
564 case wxJOIN_MITER :
565 sPenJoin = wxT("stroke-linejoin:miter; ");
566 break;
567 case wxJOIN_ROUND :
568 default :
569 sPenJoin = wxT("stroke-linejoin:round; ");
570 }
571
572 sLast.Printf( wxT("stroke-width:%d\" \n transform=\"translate(%s %s) scale(%s %s)\">"),
573 m_pen.GetWidth(), NumStr(m_logicalOriginX), NumStr(m_logicalOriginY), NumStr(m_scaleX), NumStr(m_scaleY) );
574
575 s = sBrush + sPenCap + sPenJoin + sPenStyle + sLast + wxT("\n") + sWarn;
576 write(s);
577 }
578
579
580 void wxSVGFileDCImpl::SetFont(const wxFont& font)
581
582 {
583 m_font = font;
584 }
585
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*/)
591 {
592 if (logicalFunc != wxCOPY)
593 {
594 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested nonCopy mode; this is not possible"));
595 return false;
596 }
597 if (useMask != false)
598 {
599 wxASSERT_MSG(false, wxT("wxSVGFileDC::DoBlit Call requested false mask; this is not possible"));
600 return false;
601 }
602 wxBitmap myBitmap (width, height);
603 wxMemoryDC memDC;
604 memDC.SelectObject( myBitmap );
605 memDC.Blit(0, 0, width, height, source, xsrc, ysrc);
606 memDC.SelectObject( wxNullBitmap );
607 DoDrawBitmap(myBitmap, xdest, ydest);
608 return false;
609 }
610
611 void wxSVGFileDCImpl::DoDrawIcon(const class wxIcon & myIcon, wxCoord x, wxCoord y)
612 {
613 wxBitmap myBitmap (myIcon.GetWidth(), myIcon.GetHeight() );
614 wxMemoryDC memDC;
615 memDC.SelectObject( myBitmap );
616 memDC.DrawIcon(myIcon,0,0);
617 memDC.SelectObject( wxNullBitmap );
618 DoDrawBitmap(myBitmap, x, y);
619 }
620
621 void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoord y , bool WXUNUSED(bTransparent) /*=0*/ )
622 {
623 NewGraphicsIfNeeded();
624
625 wxString sTmp, s, sPNG;
626 if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
627 wxImage::AddHandler(new wxPNGHandler);
628
629 // create suitable file name
630 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
631 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
632 while (wxFile::Exists(sPNG) )
633 {
634 m_sub_images ++;
635 sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
636 sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
637 }
638
639 //create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
640 wxBitmap myBitmap = bmp;
641 //save it
642 bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
643
644 // reference the bitmap from the SVG doc
645 // only use filename & ext
646 sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
647
648 // reference the bitmap from the SVG doc
649 int w = myBitmap.GetWidth();
650 int h = myBitmap.GetHeight();
651 sTmp.Printf ( wxT(" <image x=\"%d\" y=\"%d\" width=\"%dpx\" height=\"%dpx\" "), x,y,w,h );
652 s += sTmp;
653 sTmp.Printf ( wxT(" xlink:href=\"%s\"> \n"), sPNG.c_str() );
654 s += sTmp + wxT("<title>Image from wxSVG</title> </image>") + wxT("\n");
655
656 if (m_OK && bPNG_OK)
657 {
658 write(s);
659 }
660 m_OK = m_outfile->IsOk() && bPNG_OK;
661 }
662
663 void wxSVGFileDCImpl::write(const wxString &s)
664 {
665 const wxCharBuffer buf = s.utf8_str();
666 m_outfile->Write(buf, strlen((const char *)buf));
667 m_OK = m_outfile->IsOk();
668 }
669
670
671 #ifdef __BORLANDC__
672 #pragma warn .rch
673 #pragma warn .ccc
674 #endif
675
676 #endif // wxUSE_SVG
677