diff --git a/demos/Windows/WinFormDemo/Form1.cs b/demos/Windows/WinFormDemo/Form1.cs
index 75a6282..e31c89c 100644
--- a/demos/Windows/WinFormDemo/Form1.cs
+++ b/demos/Windows/WinFormDemo/Form1.cs
@@ -2,6 +2,7 @@
using System;
using System.ComponentModel;
using System.Drawing;
+using System.IO;
using System.Windows.Forms;
namespace WinFormDemo
@@ -12,6 +13,7 @@ public partial class Form1 : Form
private ToolStripMenuItem staticToolStripMenuItem;
private Timer timer1;
private IContainer components;
+ private ToolStripMenuItem tosvgstreamToolStripMenuItem;
private ToolStripMenuItem animatedToolStripMenuItem;
public Form1()
@@ -19,7 +21,15 @@ public Form1()
InitializeComponent();
}
- bool displayStaticExample = true;
+ private enum example_t
+ {
+ static_example = 0,
+ animated_example = 1,
+ to_svg_stream_example = 2
+ }
+
+ private example_t example_type = example_t.static_example;
+
protected override void OnPaintBackground(PaintEventArgs e)
{
@@ -29,14 +39,61 @@ protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
- if (displayStaticExample)
+ if (example_type == example_t.static_example)
{
DrawStatic(e);
}
- else
+ else if (example_type == example_t.animated_example)
{
DrawAnimated(e);
}
+ else if (example_type == example_t.to_svg_stream_example)
+ {
+ DrawStaticAndToOutputStream();
+ }
+ }
+
+ private void DrawStaticAndToOutputStream()
+ {
+ MemoryStream outpStream = new MemoryStream();
+ // create a SvgSurface, which output is bound to a stream.
+ var svgStreamSurface = SvgSurface.CreateForStream(outpStream, 1024, 1024);
+ using (Context context = new Context(svgStreamSurface))
+ {
+ //clear the background to white
+ context.SetSourceRGB(1, 1, 1);
+ context.Paint();
+
+ //stroke the bug
+ context.LineWidth = 2.0;
+ context.SetSourceColor(this.bugColor);
+ context.MoveTo(7.0, 64.0);
+ context.CurveTo(1.0, 47.0, 2.0, 46.0, 9.0, 51.0);
+ context.MoveTo(25.0, 80.0);
+ context.CurveTo(10.0, 73.0, 11.0, 70.0, 14.0, 63.0);
+ context.MoveTo(10.0, 41.0);
+ context.CurveTo(2.0, 36.0, 1.0, 33.0, 1.0, 26.0);
+ context.LineWidth = 1.0;
+ context.MoveTo(1.0, 26.0);
+ context.CurveTo(5.0, 23.0, 7.0, 18.0, 12.0, 17.0);
+ context.LineTo(12.0, 14.0);
+ context.Stroke();
+ context.MoveTo(30.0, 74.0);
+ context.CurveTo(14.0, 64.0, 10.0, 48.0, 11.0, 46.0);
+ context.LineTo(10.0, 45.0);
+ context.LineTo(10.0, 40.0);
+ context.CurveTo(13.0, 37.0, 15.0, 35.0, 19.0, 34.0);
+ context.Stroke();
+ }
+ // .Finish() is mandatory. Without this, cairo does not write anything to the stream.
+ svgStreamSurface.Finish();
+
+ outpStream.Seek(0, SeekOrigin.Begin);
+ StreamReader reader = new StreamReader(outpStream);
+
+ Console.WriteLine(reader.ReadToEnd());
+
+ timer1.Enabled = false;
}
private Cairo.Color bugColor = new Cairo.Color(0.95294117647058818, 0.6, 0.0784313725490196, 1.0);
@@ -119,6 +176,7 @@ private void InitializeComponent()
this.staticToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.animatedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.timer1 = new System.Windows.Forms.Timer(this.components);
+ this.tosvgstreamToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
@@ -126,7 +184,8 @@ private void InitializeComponent()
//
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.staticToolStripMenuItem,
- this.animatedToolStripMenuItem});
+ this.animatedToolStripMenuItem,
+ this.tosvgstreamToolStripMenuItem});
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
this.menuStrip1.Name = "menuStrip1";
this.menuStrip1.Size = new System.Drawing.Size(284, 24);
@@ -152,6 +211,13 @@ private void InitializeComponent()
this.timer1.Interval = 30;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
+ // tosvgstreamToolStripMenuItem
+ //
+ this.tosvgstreamToolStripMenuItem.Name = "tosvgstreamToolStripMenuItem";
+ this.tosvgstreamToolStripMenuItem.Size = new System.Drawing.Size(84, 20);
+ this.tosvgstreamToolStripMenuItem.Text = "tosvgstream";
+ this.tosvgstreamToolStripMenuItem.Click += new System.EventHandler(this.tosvgstreamToolStripMenuItem_Click_1);
+ //
// Form1
//
this.ClientSize = new System.Drawing.Size(284, 261);
@@ -167,14 +233,14 @@ private void InitializeComponent()
private void staticToolStripMenuItem_Click(object sender, EventArgs e)
{
- displayStaticExample = true;
+ example_type = example_t.static_example;
timer1.Enabled = false;
this.Invalidate();
}
private void animatedToolStripMenuItem_Click(object sender, EventArgs e)
{
- displayStaticExample = false;
+ example_type = example_t.animated_example;
timer1.Enabled = true;
this.Invalidate();
}
@@ -183,5 +249,12 @@ private void timer1_Tick(object sender, EventArgs e)
{
this.Invalidate();
}
+
+ private void tosvgstreamToolStripMenuItem_Click_1(object sender, EventArgs e)
+ {
+ example_type = example_t.to_svg_stream_example;
+ timer1.Enabled = true;
+ this.Invalidate();
+ }
}
}
diff --git a/source/CairoSharp/NativeMethods.cs b/source/CairoSharp/NativeMethods.cs
index 89301eb..d3afcb2 100644
--- a/source/CairoSharp/NativeMethods.cs
+++ b/source/CairoSharp/NativeMethods.cs
@@ -350,26 +350,40 @@ static NativeMethods()
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Status cairo_read_func_t(IntPtr closure, IntPtr data, int length);
- ///
+
+ ///
+ /// cairo_write_func_t is the type of function which is called when a backend needs to write data to an output stream.
+ ///
+ /// the output closure
+ /// data to write to the stream
+ /// length of data, which should be written to stream
+ ///
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ internal delegate Status cairo_write_func_t(IntPtr closure, IntPtr data, int length);
+
+ ///
/// Creates a new image surface from PNG data read incrementally via the read_func function.
- ///
+ ///
/// function called to read the data of the file
/// data to pass to read_func
/// new cairo_surface_t or nil
///
///
- /// cairo_surface_t * cairo_image_surface_create_from_png_stream(
- /// cairo_read_func_t read_func,
+ /// cairo_surface_t * cairo_image_surface_create_from_png_stream(
+ /// cairo_read_func_t read_func,
/// void *closure);
///
- /// a new cairo_surface_t initialized with the contents of the PNG file or a "nil" surface if the data read is not a valid PNG image or memory could not be allocated for the operation. A nil surface can be checked for with cairo_surface_status(surface) which may return one of the following values:
- /// CAIRO_STATUS_NO_MEMORY CAIRO_STATUS_READ_ERROR
- /// Alternatively, you can allow errors to propagate through the drawing operations and check the status on the context upon completion using cairo_status().
- ///
- [DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
+ /// a new cairo_surface_t initialized with the contents of the PNG file or a "nil" surface if the data read is not a valid PNG image or memory could not be allocated for the operation. A nil surface can be checked for with cairo_surface_status(surface) which may return one of the following values:
+ /// CAIRO_STATUS_NO_MEMORY CAIRO_STATUS_READ_ERROR
+ /// Alternatively, you can allow errors to propagate through the drawing operations and check the status on the context upon completion using cairo_status().
+ ///
+ [DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
internal static extern IntPtr cairo_image_surface_create_from_png_stream ([MarshalAs(UnmanagedType.FunctionPtr)]cairo_read_func_t read_func, IntPtr closure);
- [DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
+ [DllImport(cairo, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr cairo_svg_surface_create_for_stream([MarshalAs(UnmanagedType.FunctionPtr)]cairo_write_func_t write_func, IntPtr closure, double width_in_points, double height_in_points);
+
+ [DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
internal static extern IntPtr cairo_image_surface_get_data (IntPtr surface);
[DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
@@ -962,9 +976,6 @@ static NativeMethods()
[DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
internal static extern IntPtr cairo_svg_surface_create (string fileName, double width, double height);
- //[DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
- //internal static extern IntPtr cairo_svg_surface_create_for_stream (double width, double height);
-
[DllImport (cairo, CallingConvention=CallingConvention.Cdecl)]
internal static extern IntPtr cairo_svg_surface_restrict_to_version (IntPtr surface, SvgVersion version);
diff --git a/source/CairoSharp/SvgSurface.cs b/source/CairoSharp/SvgSurface.cs
index bf052ac..1b6c05b 100644
--- a/source/CairoSharp/SvgSurface.cs
+++ b/source/CairoSharp/SvgSurface.cs
@@ -8,6 +8,8 @@
// Licensed under the GNU LGPL v3, see LICENSE for more infomation.
#endregion
using System;
+using System.IO;
+using System.Runtime.InteropServices;
namespace Cairo {
@@ -22,11 +24,41 @@ public SvgSurface (string filename, double width, double height)
{
}
- public void RestrictToVersion (SvgVersion version)
+ public void RestrictToVersion (SvgVersion version)
{
CheckDisposed ();
NativeMethods.cairo_svg_surface_restrict_to_version (Handle, version);
}
- }
+
+ #region Streaming surface
+ private NativeMethods.cairo_write_func_t write_func { get; set; }
+ public static SvgSurface CreateForStream(Stream stream, double width, double height)
+ {
+ var write_func = CreateWriteFunc(stream);
+ // keep a reference to write_func in a property, otherwise it may be garbage-collected
+ // before it is called from native side.
+ return new SvgSurface(NativeMethods.cairo_svg_surface_create_for_stream(
+ write_func, IntPtr.Zero, width, height), true) {write_func = write_func};
+ }
+ private static NativeMethods.cairo_write_func_t CreateWriteFunc(Stream stream)
+ {
+ if(stream == null || !stream.CanWrite)
+ throw new ArgumentException();
+
+ return (closure, in_data, length) =>
+ {
+ if (length == 0)
+ return Status.Success;
+
+ byte[] tempBuff = new byte[length];
+ Marshal.Copy(in_data, tempBuff, 0, length);
+
+ stream.Write(tempBuff, 0, tempBuff.Length);
+
+ return Status.Success;
+ };
+ }
+ #endregion
+ }
}