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