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