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