diff --git a/docs/changes.txt b/docs/changes.txt
index 9393c6ce65..1120a44832 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -26,6 +26,7 @@ All:
All (GUI):
- XRC handler for wxAuiToolBar added (Kinaou Hervé, David Hart).
+- Add support for embedding bitmaps in generated SVG in wxSVGFileDC (iwbnwif).
- Add support for sorting wxDataViewCtrl by multiple columns (Trigve).
- Add wxHtmlWindow::SetDefaultHTMLCursor() (Jeff A. Marr).
- Add default ctor and Create() to wxContextHelpButton (Hanmac).
diff --git a/include/wx/dcsvg.h b/include/wx/dcsvg.h
index c6485ff131..4f79708908 100644
--- a/include/wx/dcsvg.h
+++ b/include/wx/dcsvg.h
@@ -25,10 +25,43 @@
class WXDLLIMPEXP_FWD_BASE wxFileOutputStream;
-
-
class WXDLLIMPEXP_FWD_CORE wxSVGFileDC;
+// Base class for bitmap handlers used by wxSVGFileDC, used by the standard
+// "embed" and "link" handlers below but can also be used to create a custom
+// handler.
+class WXDLLIMPEXP_CORE wxSVGBitmapHandler
+{
+public:
+ // Write the representation of the given bitmap, appearing at the specified
+ // position, to the provided stream.
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const = 0;
+
+ virtual ~wxSVGBitmapHandler() {}
+};
+
+// Predefined standard bitmap handler: creates a file, stores the bitmap in
+// this file and uses the file URI in the generated SVG.
+class WXDLLIMPEXP_CORE wxSVGBitmapFileHandler : public wxSVGBitmapHandler
+{
+public:
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const;
+};
+
+// Predefined handler which embeds the bitmap (base64-encoding it) inside the
+// generated SVG file.
+class WXDLLIMPEXP_CORE wxSVGBitmapEmbedHandler : public wxSVGBitmapHandler
+{
+public:
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const;
+};
+
class WXDLLIMPEXP_CORE wxSVGFileDCImpl : public wxDCImpl
{
public:
@@ -94,6 +127,8 @@ public:
virtual void* GetHandle() const { return NULL; }
+ void SetBitmapHandler(wxSVGBitmapHandler* handler);
+
private:
virtual bool DoGetPixel(wxCoord, wxCoord, wxColour *) const
{
@@ -197,6 +232,7 @@ private:
bool m_graphics_changed; // set by Set{Brush,Pen}()
int m_width, m_height;
double m_dpi;
+ wxSVGBitmapHandler* m_bmp_handler; // class to handle bitmaps
// The clipping nesting level is incremented by every call to
// SetClippingRegion() and reset when DestroyClippingRegion() is called.
@@ -220,6 +256,11 @@ public:
: wxDC(new wxSVGFileDCImpl(this, filename, width, height, dpi))
{
}
+
+ // wxSVGFileDC-specific methods:
+
+ // Use a custom bitmap handler: takes ownership of the handler.
+ void SetBitmapHandler(wxSVGBitmapHandler* handler);
};
#endif // wxUSE_SVG
diff --git a/interface/wx/dcsvg.h b/interface/wx/dcsvg.h
index 23ad44c6b4..ffaa3d82ae 100644
--- a/interface/wx/dcsvg.h
+++ b/interface/wx/dcsvg.h
@@ -21,9 +21,12 @@
is a write-only class.
As the wxSVGFileDC is a vector format, raster operations like GetPixel()
- are unlikely to be supported. However, the SVG specification allows for PNG
- format raster files to be embedded in the SVG, and so bitmaps, icons and
- blit operations in wxSVGFileDC are supported.
+ are unlikely to be supported. However, the SVG specification allows for
+ raster files to be embedded in the SVG, and so bitmaps, icons and blit
+ operations in wxSVGFileDC are supported. By default only PNG format bitmaps
+ are supported and these are saved as separate files in the same folder
+ as the SVG file, however it is possible to change this behaviour by
+ replacing the built in bitmap handler using wxSVGFileDC::SetBitmapHandler().
A more substantial SVG library (for reading and writing) is available at
the wxArt2D website .
@@ -31,6 +34,7 @@
@library{wxcore}
@category{dc}
*/
+
class wxSVGFileDC : public wxDC
{
public:
@@ -60,6 +64,28 @@ public:
*/
void Clear();
+ /**
+ Replaces the default bitmap handler with @a handler.
+
+ By default, an object of wxSVGBitmapFileHandler class is used as bitmap
+ handler. You may want to replace it with an object of predefined
+ wxSVGBitmapEmbedHandler class to embed the bitmaps in the generated SVG
+ instead of storing them in separate files like this:
+ @code
+ mySVGFileDC->SetBitmapHandler(new wxSVGBitmapEmbedHandler());
+ @endcode
+
+ or derive your own bitmap handler class and use it if you need to
+ customize the bitmap handling further.
+
+ @param handler The new bitmap handler. If non-NULL, this object takes
+ ownership of this handler and will delete it when it is not needed
+ any more.
+
+ @since 3.1.0
+ */
+ void SetBitmapHandler(wxSVGBitmapHandler* handler);
+
/**
Does the same as wxDC::SetLogicalFunction(), except that only wxCOPY is
available. Trying to set one of the other values will fail.
@@ -117,3 +143,79 @@ public:
//@}
};
+/**
+ Abstract base class for handling bitmaps inside a wxSVGFileDC.
+
+ To use it you need to derive a new class from it and override
+ ProcessBitmap() to generate a properly a formed SVG image element (see
+ http://www.w3.org/TR/SVG/struct.html#ImageElement).
+
+ Two example bitmap handlers are provided in wx/dcsvg.h. The first (default)
+ handler will create PNG files in the same folder as the SVG file and uses
+ links to them in the SVG. The second handler (wxSVGBitmapEmbedHandler) will
+ embed the PNG image in the SVG file using base 64 encoding.
+
+ The handler can be changed by calling wxSVGFileDC::SetBitmapHandler().
+
+ @library{wxcore}
+ @category{dc}
+
+ @since 3.1.0
+*/
+class wxSVGBitmapHandler
+{
+public:
+ /**
+ Writes the bitmap representation as SVG to the given stream.
+
+ The XML generated by this function will be inserted into the SVG file
+ inline with the XML generated by the main wxSVGFileDC class so it is
+ important that the XML is properly formed.
+
+ @param bitmap A valid bitmap to add to SVG.
+ @param x Horizontal position of the bitmap.
+ @param y Vertical position of the bitmap.
+ @param stream The stream to write SVG contents to.
+ */
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const = 0;
+};
+
+/**
+ Handler embedding bitmaps as base64-encoded PNGs into the SVG.
+
+ @see wxSVGFileDC::SetBitmapHandler().
+
+ @library{wxcore}
+ @category{dc}
+
+ @since 3.1.0
+*/
+class wxSVGBitmapEmbedHandler : public wxSVGBitmapHandler
+{
+public:
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const;
+};
+
+/**
+ Handler saving a bitmap to an external file and linking to it from the SVG.
+
+ This handler is used by default by wxSVGFileDC.
+
+ @see wxSVGFileDC::SetBitmapHandler().
+
+ @library{wxcore}
+ @category{dc}
+
+ @since 3.1.0
+*/
+class wxSVGBitmapFileHandler : public wxSVGBitmapHandler
+{
+public:
+ virtual bool ProcessBitmap(const wxBitmap& bitmap,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const;
+};
diff --git a/src/common/dcsvg.cpp b/src/common/dcsvg.cpp
index 5c55a0b935..561791435b 100644
--- a/src/common/dcsvg.cpp
+++ b/src/common/dcsvg.cpp
@@ -23,9 +23,11 @@
#include "wx/image.h"
#endif
+#include "wx/base64.h"
#include "wx/dcsvg.h"
#include "wx/wfstream.h"
#include "wx/filename.h"
+#include "wx/mstream.h"
#include "wx/private/markupparser.h"
@@ -109,6 +111,105 @@ wxString wxBrushString(wxColour c, int style = wxBRUSHSTYLE_SOLID)
} // anonymous namespace
+// ----------------------------------------------------------------------------
+// wxSVGBitmapEmbedHandler
+// ----------------------------------------------------------------------------
+
+bool
+wxSVGBitmapEmbedHandler::ProcessBitmap(const wxBitmap& bmp,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const
+{
+ static int sub_images = 0;
+
+ if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
+ wxImage::AddHandler(new wxPNGHandler);
+
+ // write the bitmap as a PNG to a memory stream and Base64 encode
+ wxMemoryOutputStream mem;
+ bmp.ConvertToImage().SaveFile(mem, wxBITMAP_TYPE_PNG);
+ wxString data = wxBase64Encode(mem.GetOutputStreamBuffer()->GetBufferStart(),
+ mem.GetSize());
+
+ // write image meta information
+ wxString s;
+ s += wxString::Format(" "; // last line
+ }
+
+ // write to the SVG file
+ const wxCharBuffer buf = s.utf8_str();
+ stream.Write(buf, strlen((const char *)buf));
+
+ return stream.IsOk();
+}
+
+// ----------------------------------------------------------
+// wxSVGBitmapFileHandler
+// ----------------------------------------------------------
+
+bool
+wxSVGBitmapFileHandler::ProcessBitmap(const wxBitmap& bmp,
+ wxCoord x, wxCoord y,
+ wxOutputStream& stream) const
+{
+ static int sub_images = 0;
+
+ if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
+ wxImage::AddHandler(new wxPNGHandler);
+
+ // find a suitable file name
+ wxString sPNG;
+ do
+ {
+ sPNG = wxString::Format("image%d.png", sub_images++);
+ }
+ while (wxFile::Exists(sPNG));
+
+ if ( !bmp.SaveFile(sPNG, wxBITMAP_TYPE_PNG) )
+ return false;
+
+ // reference the bitmap from the SVG doc using only filename & ext
+ sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
+
+ // reference the bitmap from the SVG doc
+ wxString s;
+ s += wxString::Format(" \n\n", sPNG);
+
+ // write to the SVG file
+ const wxCharBuffer buf = s.utf8_str();
+ stream.Write(buf, strlen((const char *)buf));
+
+ return stream.IsOk();
+}
+
+// ----------------------------------------------------------
+// wxSVGFileDC (specialisations)
+// ----------------------------------------------------------
+
+void wxSVGFileDC::SetBitmapHandler(wxSVGBitmapHandler* handler)
+{
+ ((wxSVGFileDCImpl*)GetImpl())->SetBitmapHandler(handler);
+}
+
// ----------------------------------------------------------
// wxSVGFileDCImpl
// ----------------------------------------------------------
@@ -150,6 +251,7 @@ void wxSVGFileDCImpl::Init (const wxString &filename, int Width, int Height, dou
////////////////////code here
+ m_bmp_handler = NULL;
m_outfile = new wxFileOutputStream(filename);
m_OK = m_outfile->IsOk();
if (m_OK)
@@ -570,6 +672,11 @@ void wxSVGFileDCImpl::SetBackgroundMode( int mode )
m_backgroundMode = mode;
}
+void wxSVGFileDCImpl::SetBitmapHandler(wxSVGBitmapHandler* handler)
+{
+ delete m_bmp_handler;
+ m_bmp_handler = handler;
+}
void wxSVGFileDCImpl::SetBrush(const wxBrush& brush)
{
@@ -686,42 +793,11 @@ void wxSVGFileDCImpl::DoDrawBitmap(const class wxBitmap & bmp, wxCoord x, wxCoor
{
NewGraphicsIfNeeded();
- wxString sTmp, s, sPNG;
- if ( wxImage::FindHandler(wxBITMAP_TYPE_PNG) == NULL )
- wxImage::AddHandler(new wxPNGHandler);
+ // If we don't have any bitmap handler yet, use the default one.
+ if ( !m_bmp_handler )
+ m_bmp_handler = new wxSVGBitmapFileHandler();
-// create suitable file name
- sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
- sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
- while (wxFile::Exists(sPNG) )
- {
- m_sub_images ++;
- sTmp.Printf ( wxT("_image%d.png"), m_sub_images);
- sPNG = m_filename.BeforeLast(wxT('.')) + sTmp;
- }
-
-//create copy of bitmap (wxGTK doesn't like saving a constant bitmap)
- wxBitmap myBitmap = bmp;
-//save it
- bool bPNG_OK = myBitmap.SaveFile(sPNG,wxBITMAP_TYPE_PNG);
-
-// reference the bitmap from the SVG doc
-// only use filename & ext
- sPNG = sPNG.AfterLast(wxFileName::GetPathSeparator());
-
-// reference the bitmap from the SVG doc
- int w = myBitmap.GetWidth();
- int h = myBitmap.GetHeight();
- sTmp.Printf ( wxT(" \n"), sPNG.c_str() );
- s += sTmp + wxT("Image from wxSVG ") + wxT("\n");
-
- if (m_OK && bPNG_OK)
- {
- write(s);
- }
- m_OK = m_outfile->IsOk() && bPNG_OK;
+ m_bmp_handler->ProcessBitmap(bmp, x, y, *m_outfile);
}
void wxSVGFileDCImpl::write(const wxString &s)