Git Product home page Git Product logo

ngraphics's Introduction

NGraphics

NuGet Package Build

NGraphics is a cross platform library for rendering vector graphics on .NET. It provides a unified API for both immediate and retained mode graphics using high quality native renderers.

You can use it for cross platform rendering of UI widgets. Or as the basis for graphically rich interactive views. Or maybe you just want an easy way to import and export SVG and PNG files. Either way, I'm sure you'll find something interesting here.

Installation

Install NGraphics from nuget.

Getting Started

The most important class is ICanvas. Uses canvases to render vector graphics (rectangles, ellipses, paths) to "something". Sometimes canvases are views on the screen, sometimes they are images -- you never really know.

We can draw a little house easily enough:

var canvas = Platforms.Current.CreateImageCanvas (new Size (100), scale: 2);

var skyBrush = new LinearGradientBrush (Point.Zero, Point.OneY, Colors.Blue, Colors.White);
canvas.FillRectangle (new Rect (canvas.Size), skyBrush);
canvas.FillEllipse (10, 10, 30, 30, Colors.Yellow);
canvas.FillRectangle (50, 60, 60, 40, Colors.LightGray);
canvas.FillPath (new PathOp[] {	
	new MoveTo (40, 60),
	new LineTo (120, 60),
	new LineTo (80, 30),
	new ClosePath ()
}, Colors.Gray);

canvas.GetImage ().SaveAsPng (GetPath ("Example1.png"));

Platforms.Current.CreateImageCanvas is just our tricky way to get a platform-specific ICanvas that we can rendered on. IImageCanvases are special because you can call GetImage to get an image of the drawing when you are done. We use a scale of 2 to render retina graphics and keep this README looking good.

Paths are drawn using standard turtle graphics.

Pens and Brushes

When drawing, you have a choice of pens to stroke the object with or brushes to fill it with.

Anyway.

Pens can be any color and any width.

var canvas = Platforms.Current.CreateImageCanvas (new Size (120*5, 120), scale: 2);

canvas.Translate (20, 20);
for (var i = 0; i < 5; i++) {
	canvas.DrawEllipse (
		new Rect (new Size (80)),
		pen: Pens.DarkGray.WithWidth (1 << i),
		brush: Brushes.LightGray);
	canvas.Translate (120, 0);
}

canvas.GetImage ().SaveAsPng (GetPath ("PenWidths.png"));

Brushes can be solid colors or trippy multi-color gradients (linear and radial!)

There is no multi-layering within elements, so you will have to draw them a few times with different brushes to get complex effects.

Colors

What would a graphics library be without a Color class? Well, this one is a struct. Colors are light-weight, have fun with them.

Normally you will use the RGBA constructor of color: new Color (r, g, b, a) where each value can range from 0 to 1.

If you're not normal, you might prefer the web notation: Color.FromRGB (0xBEEFEE).

Retained Mode

Sometimes it's nice to hang onto the graphical elements themselves so that you can change them later, or perhaps cache them from an expensive-to-compute draw operation, or maybe you just want to sing to them. Whatever your needs, NGraphics exposes the following graphical elements:

  • Rectangles are best used for drawing rectangles.
  • Ellipses can also be used to draw ovals and circles.
  • Paths can draw anything that you can imagine, and more. Lines, curves, turtles, they're all for the taking.
var circle = new Ellipse (new Rectangle (Point.Zero, new Size (10)));

ICanvas canvas = ...;
circle.Draw (canvas);

Platforms

  • Android (Xamarin) using Android.Graphics
    • CanvasCanvas wraps a Android.Graphics.Canvas
  • iOS (Xamarin) using CoreGraphics
    • CGContextCanvas wraps a CoreGraphics.CGContext
  • Mac (Xamarin) using CoreGraphics
    • CGContextCanvas wraps a CoreGraphics.CGContext
  • .NET 4.5 using System.Drawing
    • GraphicsCanvas wraps a System.Drawing.Graphics
  • Windows Store 8.1 using Direct2D
    • RenderTargetCanvas wraps a SharpDX.Direct2D1.RenderTarget
  • Windows Phone 8.1 using Direct2D
    • RenderTargetCanvas wraps a SharpDX.Direct2D1.RenderTarget
  • Universal Windows Platform (UWP) using Direct2D
    • RenderTargetCanvas wraps a SharpDX.Direct2D1.RenderTarget

Editor

To speed up the process of drawing with code, NGraphics ships with a code editor and live preview for OS X. Download the editor from the Releases page.

Any C# file that can be independently compiled can be used. The advantage of this editor over Xamarin Studio is that you can work on your drawings without having to wait for your whole project to compile and run.

Simply compile and run the project NGraphics.Editor or download the editor to get started.

Examples

For more examples, check out the images in the TestResults directory and the test code that generated them.

Icon

The NGraphics icon can be rendered using a simple repeating path:

var size = new Size (64);
var canvas = Platforms.Current.CreateImageCanvas (size, scale: 2);
canvas.SaveState ();
canvas.Scale (size);
canvas.Translate (1 / 8.0, 0);

var p = new Path ();
p.MoveTo (0, 1);
p.LineTo (0, 0);
p.LineTo (0.5, 1);
p.LineTo (0.5, 0);

var colors = new [] {
	"#DCDCDD",
	"#C5C3C6",
	"#46494C",
	"#4C5C68",
	"#68A5E2",
};
foreach (var c in colors) {
	p.Pen = new Pen (c, 1 / 4.0);
	p.Draw (canvas);
	canvas.Translate (1 / 16.0, 0);
}

canvas.GetImage ().SaveAsPng (GetPath ("Icon.png"));

Cats

NGraphics also supports scaling cats:

var img = GetResourceImage ("cat.png");
var canvas = Platform.CreateImageCanvas (new Size (100, 200), transparency: true);
canvas.DrawImage (img, new Rect (new Size (50)));
canvas.DrawImage (img, new Rect (new Point (50, 0), new Size (50)));
canvas.DrawImage (img, new Rect (new Point (0, 50), new Size (50, 150)));
canvas.DrawImage (img, new Rect (new Point (50, 50), new Size (50, 150)));
canvas.GetImage ().SaveAsPng (GetPath ("ImageCanvas.Cats"));

License

The MIT License (MIT)

See LICENSE for details.

ngraphics's People

Contributors

ahopper-soltech avatar chamons avatar chrfalch avatar clancey avatar claudiuslollarius avatar jomar avatar kirksqor avatar michaelstonis avatar praeclarum avatar richlander avatar ryanfielder avatar vinorr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ngraphics's Issues

Incorrect decoding of coordinates in SVG path parameters

The following SVG image is not processed correctly by the SvgReader:

<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
	<path d="M13.25 21.59c2.88 5.66 7.51 10.29 13.18 13.17l4.4-4.41c.55-.55 1.34-.71 2.03-.49C35.1 30.6 37.51 31 40 31c1.11 0 2 .89 2 2v7c0 1.11-.89 2-2 2C21.22 42 6 26.78 6 8c0-1.11.9-2 2-2h7c1.11 0 2 .89 2 2 0 2.49.4 4.9 1.14 7.14.22.69.06 1.48-.49 2.03l-4.4 4.42z" fill="#000000" fill-opacity="0.54" />
</svg>

The issue is with one of the 'c' (curveto) commands in the path: c0-1.11.9-2 2-2. More concretely, the reader cannot correctly decode the block -1.11.9 which includes multiple coordinates not separated by wsp.

System.ArgumentNullException: Argument cannot be null [IOS Only]

I get the following error when using NGraphics to draw a canvas and get the PNG from it. I draw an image from a bytearray to the canvas, some text, and then save the image to a memorystream. This crash only occurs on iOS:

System.ArgumentNullException: Argument cannot be null.
Parameter name: image
  at NGraphics.CGImageImage..ctor (CoreGraphics.CGImage image, Double scale) [0x0000c] in /Users/fak/Dropbox/Projects/NGraphics/Platforms/NGraphics.Mac/ApplePlatform.cs:133
  at NGraphics.ApplePlatform.LoadImage (System.IO.Stream stream) [0x0005e] in /Users/fak/Dropbox/Projects/NGraphics/Platforms/NGraphics.Mac/ApplePlatform.cs:77
  at GroupieCross.ViewModels.CameraViewPageViewModel+<HandleBitmap>c__async4.MoveNext () [0x00000] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross/ViewModel/ViewModelLocator.cs:11
  at --- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003b] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:199
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142
  at System.Runtime.CompilerServices.TaskAwaiter`1[System.Byte[]].GetResult () [0x00000] in <filename unknown>:0
  at GroupieCross.ViewModels.CameraViewPageViewModel+<Accept>c__async1.MoveNext () [0x00013] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross/ViewModels/GroupMessagePageViewModel.cs:37
  at --- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000b] in /Users/builder/data/lanes/1503/6481535e/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>m__0 (System.Object state) [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1006
  at UIKit.UIKitSynchronizationContext+<Post>c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIKitSynchronizationContext.cs:24
  at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/Foundation/NSAction.cs:164
  at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
  at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIApplication.cs:63
  at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0001c] in /Users/builder/data/lanes/1503/6481535e/source/maccore/src/UIKit/UIApplication.cs:46
  at GroupieCross.Application.Main (System.String[] args) [0x00020] in /Users/frankgeib/Desktop/GroupieCross/GroupieCross/GroupieCross.iOS/AppDelegate.cs:25

Android ArcTo implementation starts a new contour instead of continuing previous one

The Android implementation of ICanvas.ArcTo calls Android.Graphics.Path.AddArc. However, this method adds the arc as a new contour, which means it first closes the path up to that point before continuing. This doesn't seem like a very useful behavior, but that's what it does.

You can see the issue by trying to draw a circle using four consecutive arcs:

var w = 10;
var h = 10;
var r = w/2;
var arcSize = new NGraphics.Size(r, r);
var path = new PathOp []
{ 
    new MoveTo(w / 2, 0),
    new ArcTo(arcSize, false, true, new NGraphics.Point(w, h / 2)),
    new ArcTo(arcSize, false, true, new NGraphics.Point(w / 2, h)),
    new ArcTo(arcSize, false, true, new NGraphics.Point(0, h / 2)),
    new ArcTo(arcSize, false, true, new NGraphics.Point(w / 2, 0)),
    new ClosePath(),
};
canvas.DrawPath(path, null, brush);

The result is a circle with a diamond-shaped hole in it (each 1/4 arc was closed prior to starting the next arc).

Unfortunately, the Android.Graphics.Path.ArcTo method appears to have the same behavior (so why are there two different methods?). So I'm not sure what the appropriate fix is here.

Arc from SVG is broken into segments

I have an SVG I drew in Inkscape with several arcs and all of them are broken into segments


    <path
       style="opacity:1;fill:#00ff00;fill-opacity:0.06267808;stroke:#00ff00;stroke-width:25;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
       sodipodi:type="arc"
       sodipodi:cx="415"
       sodipodi:cy="239.10849"
       sodipodi:rx="82.14286"
       sodipodi:ry="84.64286"
       sodipodi:start="0.32075808"
       sodipodi:end="4.34342"
       d="m 492.9533,265.7952 a 82.14286,84.64286 0 0 1 -85.40564,57.60709 82.14286,84.64286 0 0 1 -73.89757,-72.56127 82.14286,84.64286 0 0 1 51.72476,-90.6789"/>

and here's how it renders: https://www.dropbox.com/s/qzsildc00xtlrsy/Screen%20Shot%202017-01-22%20at%203.43.54%20PM.PNG?dl=0

I don't mind fixing the problem in NGraphics' code, any ideas what the issue may be and what's happening?

Store color as HSV instead of RGB

Why:
NGraphics.Color stores data in 3 bytes called R, G, B. This method of data storage is destructive.

Explanation:
If you convert the HSV value black, X, Y, 0 (where X and Y are variables), it will get converted to 0, 0, 0 in RGB. When you attempt to convert back the color to HSV, it does not have sufficient data to reconstruct the original HSV value and will default to 0, 0, 0 in HSV, thereby losing the origin X and Y values. However if the data was stored as HSV, it can easily reconstruct the original RGB value.

This method of storing also results in a lot of rounding errors for all the Hue, Saturation, and Value values.

Opacity not supported

opacity, fill-opacity and stroke-opacity not supported, causes really awkward rendering of SVGs that use it

Does not build from master.

Trying to build from master on VS 2015 RC does not work. I'm getting the following errors:

2>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(59,38,59,44): error CS0535: 'WICBitmapSourceImage' does not implement interface member 'IImage.Size'
2>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(59,38,59,44): error CS0535: 'WICBitmapSourceImage' does not implement interface member 'IImage.Scale'
2>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(19,53,19,65): error CS0535: 'WICBitmapCanvas' does not implement interface member 'ICanvas.MeasureText(string, Font)'
2>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(118,36,118,43): error CS0535: 'RenderTargetCanvas' does not implement interface member 'ICanvas.MeasureText(string, Font)'
1>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(59,38,59,44): error CS0535: 'WICBitmapSourceImage' does not implement interface member 'IImage.Size'
1>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(59,38,59,44): error CS0535: 'WICBitmapSourceImage' does not implement interface member 'IImage.Scale'
1>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(19,53,19,65): error CS0535: 'WICBitmapCanvas' does not implement interface member 'ICanvas.MeasureText(string, Font)'
1>D:\projects\NGraphics\Platforms\NGraphics.WindowsStore\Direct2DCanvas.cs(118,36,118,43): error CS0535: 'RenderTargetCanvas' does not implement interface member 'ICanvas.MeasureText(string, Font)'

Indeed it seems these methods aren't implemented.

Color class is inconsistent about premultiplication

new Color(r, g, b) is not the same as Color.FromRGB(rgb). This confused the heck out of me. It looks like there is some premultiplication going on in FromRGB but not in the ctors.

I wanted to add an alpha value to Color.FromRGB(), but there is no overload that takes an alpha value, so I switched to some of the ctors and found out the hard way that they don't premultiply. So I had to use Color.FromRGB(rgb).WithAlpha(a).

I suggest a naming convention that is more explicit about premultiplication, like the Monogame Framework Color.FromNonPremultiplied methods.

I also suggest overloads that take an alpha parameter, to make it simple to create a premultiplied color that includes an alpha value in one step.

Color.FromNonPremultiplied(int r, int g, int b, int a = 255)
Color.FromNonPremultiplied(int r, int g, int b, double a = 1.0)
Color.FromNonPremultiplied(int rgb, int a = 255)
Color.FromNonPremultiplied(int rgb, double a = 1.0)
Color.FromNonPremultiplied(uint argb)

Clip function

I think it can be useful to support Clip function

SVG fill:<color> fails to parse (only on some colors...?)

Fails on the style fill:blue (using OS-X NGraphics.Editor to confirm)

<svg width="400" height="180">
  <rect x="10" y="10" width="100" height="100" 
  style="fill:blue;stroke:black;stroke-width:10;" />
</svg>

Fail on fill:

  • LightGray
  • DarkGray
  • Gray
  • Yellow
  • Blue
  • Green

Works on fill:

  • Clear
  • Black
  • White
  • Red
  • Orange

Project with NGraphis 0.4.0 or 0.3.1 does not pass Windows Store certification

Our application using NGraphics and SharpDX does not pass Windows Store certification because, as I understand it, its linked with debug version of the library:

The binary NGraphics.WindowsStore.dll is built in debug mode.
The binary NGraphics.dll  is built in debug mode.

Also the SharpDX library is using some incompatible API:

D2D1GetGradientMeshInteriorPointsFromCoonsPatch in d2d1.dll is not supported for this application type. SharpDX.Direct2D1.dll calls this API.
API D3D11On12CreateDevice in d3d11.dll is not supported for this application type. SharpDX.Direct3D11.dll calls this API.

Tried with NGraphics 0.3.1 and 0.4.0. Any clue how to pass Windows Store certification with NGraphics, please?

Fork

Hey @praeclarum

Just wanted to make you aware of my work. I have forked the repo :

https://github.com/paulpatarinski/NGraphics

And I have made the following changes :

  • Replaced the Svg Path Parser with the one from : https://github.com/vvvv/SVG
  • Moved some of projects into folders
  • Started adding some Sample Svgs from the W3C TestSuite
  • Introduced some more classes and tests (StylesParser,ValuesParser)
  • Added support for a couple more Commands

Would love to hear your thoughts on the changes and potentially join forces...

Paul

Direct2D on Windows

I've noticed your Windows backend is currently using System.Drawing. Would it be possible to add a Direct2D backend also on standard Windows?

Incorrect processing of SVG attribute 'fill-opacity'

The following SVG is not processed correctly by the SvgReader:

<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
  <path d="M6 18v12h8l10 10V8L14 18H6zm27 6c0-3.53-2.04-6.58-5-8.05v16.11c2.96-1.48 5-4.53 5-8.06zM28 6.46v4.13c5.78 1.72 10 7.07 10 13.41s-4.22 11.69-10 13.41v4.13c8.01-1.82 14-8.97 14-17.54S36.01 8.28 28 6.46z" fill-opacity="0.54"/>
</svg>

The 'fill-opacity' attribute in the above example is ignored.

On the other hand, the combination of 'fill' and 'fill-opacity' attributes will be correctly processed, as in the following example:

<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
  <path d="M6 18v12h8l10 10V8L14 18H6zm27 6c0-3.53-2.04-6.58-5-8.05v16.11c2.96-1.48 5-4.53 5-8.06zM28 6.46v4.13c5.78 1.72 10 7.07 10 13.41s-4.22 11.69-10 13.41v4.13c8.01-1.82 14-8.97 14-17.54S36.01 8.28 28 6.46z" fill="#000000" fill-opacity="0.54"/>
</svg>

The 'fill-opacity' attribute should be processed in both cases.

System.Windows.Media (WPF) platform support

We have a mostly complete implementation of this platform for NGraphics. It works for our purposes but is missing the ArcTo op and probably a few others. I'm mostly posting this issue as a reminder for myself to try to get a pull request or fork ready for publishing - even if still incomplete. If anyone else finds a need for this feature I'll try to get it done sooner.

Is it possible to draw on a Windows.UI.Xaml.Controls.Canvas?

I'm trying to figure out how best to use this library for a Windows Phone 8.1 app, and ideally I'd like to define a Windows.UI.Xaml.Controls.Canvas (i.e. a <Canvas /> element in my .xaml page) and draw onto that. Is that possible? How?

I can't seem to figure it out from the readme, and my google searches give too much noise for "graphics" when I try to search for stuff related to "ngraphics"...

Thanks for the help!

assistance in a project

Hi Frank
do you work as a consultant? I would like to use your library in my project
btw great work with your library

ArcTo example?

Anyone have an example on how to use ArcTo? I'm trying to draw a half circle, but I can't seem to get it to work.

My Code:

canvas.DrawPath(new PathOp []{ 
    new MoveTo(0, height/2),
    new LineTo(width, height/2),
    new ArcTo(
        new NGraphics.Size(width/2, width/2),
        true,
        true,
        new NGraphics.Point(0, height/2)
    ),
    new ClosePath()
}, null, backgroundBrush);

DrawText draws text above specified Rect

Since ICanvas.DrawText accepts a Rect as its second parameter, I would expect it to draw the text INTO the specified Rect. However, both Android and iOS draw the text directly ABOVE it. This can be reproduced by drawing both the Rect and the Text:

    canvas.DrawRectangle(textRect, brush: Brushes.Green);
    canvas.DrawText(value.ToString(), textRect, _font, TextAlignment.Center, pen, brush);

NControl's implementation for Windows Phone, however, behaves exactly how I would expect it to.

Support for WinRT?

This lib looks great, but it seems to be missing support for WinRT... System.Drawing is only available in the full desktop framework. Do you intend to support Windows Phone / Windows Store / Universal apps as well?

Missing polyline element

Missing polyline element

example
polyline fill="none" stroke="#666766" stroke-width="2" stroke-miterlimit="10" points="-68.8,92.8 -50.2,75.2 -31.3,92.8 "

Feature Request: support scalable (i.e. 9 slice) SVGs elements

Please add scalable (i.e. 9 slice) SVGs elements to NGraphics.

Let me explain what I mean by that. As you know SVG are already scalable, being vector based. For example for gradients I just use an SVG image. A simple rectangle drawn in Inkscape, where I can edit and preview all gradients colors, steps, orientation, etc. This is the svg file content:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="600" width="600" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="0 0 600 600">
 <defs>
  <linearGradient id="linearGradient4297" y2="600" gradientUnits="userSpaceOnUse" x2="300" x1="300">
   <stop stop-color="#e66aff" offset="0"/>
   <stop stop-color="#fef8ff" offset="1"/>
  </linearGradient>
 </defs>
 <rect style="color:#000000" height="600" width="600" y="0" x="0" fill="url(#linearGradient4297)"/>
</svg>

Then I use the Xamarin Forms SVG plugin with NGraphics to display it and resize it from the default size (viewBox of 600x600 pixels) to fit any Windows, iOS or Android app frame or button background.
In this way artists in my team can change all graphic elements and color themes without my intervention, just editing the SVG files in Inkscape.

A 9-slice element is something different and more complex. Is the composition of both a regular svg image, and a 3x3 grid definition associated with it. Each sub element of the 3x3 grid is flagged with one of the following tags:

  • "resizable horizontally"
  • "resizable vertically"
  • "resizable in both directions"
  • "not resizable".

The renderer of the app should be aware of this and be able to render the svg image scaled according to the grid. Usually this is used to create frame border, setting the corners of the 3x3 grid as "not resizable", the left and right elements as "resizable vertically", and the top and bottom elements as "resizable horizontally". The central element must be set to "resizable in both directions".
The Android SDK already implements this, Windows Mobile doesn't, while on iOS there is a very limited implementation (see: http://macoscope.com/blog/stretchable-images-using-interface-builder/ ).

A true cross platform implementation of this would be very useful for using 9-tiles on Xamarin.Forms.
The Xamarin.Forms plugin for SVG uses NGraphics, and then we would need to add this feature to NGraphics library. We need to add a method to associate the 3x3 grid matrix to the current loaded svg image. It would be useful to load the 3x3 grid data from the SVG image itself, using some metadata.

Currently SVG already supports 9-slice resizing, because SVG format specification includes many CSS 3 style attributes. And that is by using the CSS style attribute BORDER-IMAGE-SLICE:

https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-slice

border-image-slice

schermata 2015-07-26 alle 23 06 01

Here is an interactive example I've made on codepen of an SVG button resized with the border-image-slice attribute:

http://codepen.io/Emasoft/pen/qEsFr

It would be great to have this functionality supported by NGraphics.

Relative path operations

The relative path ops (the lower case ones) aren't supported. This is an easy fix and just need some decent test SVGs.

gradientTransform not working

I have an SVG which includes gradients and gradientTransform is not being applied. I attempted different types of transforms (instead of the matrix, as in the example below) and was unable to see any transform results. I'm testing by using the SampleApps project included with the source code to display my svg.

Here's an example of a linear gradient with the gradientTransform:

<linearGradient id="SVGID_1_" x1="36.8%" y1="99%" x2="36.8%" y2="1%" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 -1 0 512)" > 
   <stop  offset="0%" stop-color="#FFFFFF"/>  
   <stop  offset="100%" stop-color="#CCCCCC"/>
</linearGradient>

Not specifically transform bug related, it took a bit of trial and error to get my gradients working at all.
If you look at the ErulisseuiinSpaceshipPack images output by the tests, you can see that the gradients aren't being displayed correctly on android and iOS. ( https://github.com/praeclarum/NGraphics/blob/master/TestResults/ErulisseuiinSpaceshipPack.svg-Android.png )

I have found, if you use percentage based values in the SVG for x1, y1, x2, and y2, then the gradients DO display correctly on Android (haven't tried iOS yet).
For example:

<linearGradient id="SVGID_1_" x1="36.8%" y1="99%" x2="36.8%" y2="1%" gradientUnits="userSpaceOnUse" > <!-- works -->
<linearGradient id="SVGID_1_" x1="139.5005" y1="511.668" x2="139.5005" y2="4.383" gradientUnits="userSpaceOnUse" > <!-- doesn't work --> 

The other thing I found is that the package doesn't seem to like the style tag on the gradient stops.

<stop  offset="0" stop-color="#FFFFFF"/>  <!-- works -->
<stop  offset="0"  style="stop-color:#FFFFFF"/>  <!-- doesn't work -->

Maybe that info can save someone else some time.

Is there a way to recycle the bitmap

I am having out of memory when using the library. I need to show an image on a single view and when user clicked on the button , I should load a new image using LoadImage on NGraphics. On Android, I usually use image.Recycle and image.dispose before I set image object to null to clear the memory. In this IImage, I can't see a function to recycle teh memory used on the IImage.

Bug in SvgReader for paths with 'm' command after 'z' command

The following material design icon is not processed correctly by SvgReader:

<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
	<path d="M6 18v12h8l10 10V8L14 18H6zm27 6c0-3.53-2.04-6.58-5-8.05v16.11c2.96-1.48 5-4.53 5-8.06zM28 6.46v4.13c5.78 1.72 10 7.07 10 13.41s-4.22 11.69-10 13.41v4.13c8.01-1.82 14-8.97 14-17.54S36.01 8.28 28 6.46z"/>
</svg>

The problem lies in the fact that an 'm' command (relative moveto) follows a 'z' command (close). The information about the previous point in the path is lost after the 'z' command and cannot be applied to the 'm' command.

Posting here a corrected version of SvgReader.ReadPath(). However, I am not an SVG expert so please check the proposed solution for overall correctness.

void ReadPath (Path p, string pathDescriptor)
{
	Match m = pathRegex.Match(pathDescriptor);
	Point previousPoint = new Point();
	while(m.Success)
	{
		var match = m.Value.TrimStart ();
		var op = match[0];

		if (op == 'z' || op == 'Z') {
			p.Close ();
		} else {
			// make sure negative numbers are split properly
			match = negativeNumberRe.Replace(match.Substring(1), " -");
			var args = match.Split(WSC, StringSplitOptions.RemoveEmptyEntries);

			int index = 0;
			while(index < args.Length)
			{
				if ((op == 'M' || op == 'm') && args.Length >= index+2) {
					var point = new Point (ReadNumber (args [index]), ReadNumber (args [index+1]));
					if (op == 'm')
						point += previousPoint;
					p.MoveTo (point);
					index += 2;
				} else if ((op == 'L' || op == 'l') && args.Length >= index+2) {
					var point = new Point (ReadNumber (args [index]), ReadNumber (args [index+1]));
					if (op == 'l')
						point += previousPoint;
					p.LineTo (point);
					index += 2;
				} else if ((op == 'C' || op == 'c') && args.Length >= index+6) {
					var c1 = new Point (ReadNumber (args [index]), ReadNumber (args [index+1]));
					var c2 = new Point (ReadNumber (args [index+2]), ReadNumber (args [index+3]));
					var pt = new Point (ReadNumber (args [index+4]), ReadNumber (args [index+5]));
					if (op == 'c')
					{
						c1 += previousPoint;
						c2 += previousPoint;
						pt += previousPoint;
					}
					p.CurveTo (c1, c2, pt);
					index += 6;
				} else if ((op == 'S' || op == 's') && args.Length >= index+4) {
					var c  = new Point (ReadNumber (args [index]), ReadNumber (args [index+1]));
					var pt = new Point (ReadNumber (args [index+2]), ReadNumber (args [index+3]));
					if (op == 's')
					{
						c += previousPoint;
						pt += previousPoint;
					}
					p.ContinueCurveTo (c, pt);
					index += 4;
				} else if ((op == 'A' || op == 'a') && args.Length >= index+7) {
					var r = new Size (ReadNumber (args [index]), ReadNumber (args [index+1]));
					var laf = ReadNumber (args [index+3]) != 0;
					var swf = ReadNumber (args [index+4]) != 0;
					var pt = new Point (ReadNumber (args [index+5]), ReadNumber (args [index+6]));
					if (op == 'a')
						pt += previousPoint;
					p.ArcTo (r, laf, swf, pt);
					index += 7;
				} else if ((op == 'V' || op == 'v') && args.Length >= index+1 && p.Operations.Count > 0) {
					var previousX = previousPoint.X;
					var y = ReadNumber(args[index]);
					if (op == 'v')
						y += previousPoint.Y;
					var point = new Point(previousX, y);
					p.LineTo(point);
					index += 1;
				} else if ((op == 'H' || op == 'h') && args.Length >= index+1 && p.Operations.Count > 0) {
					var previousY = previousPoint.Y;
					var x = ReadNumber(args[index]);
					if (op == 'h')
						x += previousPoint.X;
					var point = new Point(x, previousY);
					p.LineTo(point);
					index += 1;
				} else {
					throw new NotSupportedException ("Path Operation " + op);
				}
				previousPoint = p.Operations.Last().EndPoint;
			}
		}
		m = m.NextMatch();
	}
}

Dotted/stippled lines

It would be great if we could have the possibility to draw stippled/dotted lines.

This could be done by setting a "pattern" parameter on the Pen, where the pattern is defined like in Android graphics: an array where each element defines the length of the stroked and non-stroked parts, respectively.

Adding NGraphics Causes iOS Build Warning

I have a Xamarin solution, which has the fairly usual format of: MyApplication (Portable), MyApplication.Forms, MyApplication.iOS and MyApplication.Droid.

It builds with no warnings or errors and has done so for some months.

If I add NGraphics 0.4.0 via the package manager in Visual Studio, I get the following build warning on the iOS build:

5>  No way to resolve conflict between "System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" and "System.Runtime.Serialization, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e". Choosing "System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" arbitrarily.
5>  Serenocalm.iOS -> \MyApp\MyApp.iOS\bin\iPhoneSimulator\Debug\MyAppiOS.exe

How can I fix this?

Kind wishes ~ Patrick

Some of my svg buttons to test the library

I use to create all my assets in SVG because it's the only scalable and crossplatform graphic format. Using them in Xamarin.Forms would finally allows a true crossplatform development.

This is how my buttons should look for reference:
ios_app_buttons

You can download the original svg file from my google drive (click on the download button):
http://goo.gl/m7TbmM

For an easier debug, here it is a splitted version of the two main buttons svg files, you can download the zip from here:
https://drive.google.com/file/d/0BxexooDWEb8ublZlcm5yRWpXTzQ/view?usp=sharing

Here are the screenshots of how each svg file should look:

schermata 2015-02-20 alle 20 28 22
schermata 2015-02-20 alle 20 27 56
schermata 2015-02-20 alle 20 24 58
schermata 2015-02-20 alle 20 24 49
schermata 2015-02-20 alle 20 24 17
schermata 2015-02-20 alle 20 23 59

SVG Rotation of circles produces wrong results

Rotation of SVG images doesn't seem to work correctly. Especially in certain angles. The following code produces visible "rounded squares" of the circle "fill"-color around the image - those squares especially become apparent at degrees 45°, 135° and so on and are invisible at degrees 0°, 90° and so on:

var svg = NGraphics.Graphic.LoadSvg(new StringReader(@"<svg version=""1.1"" id=""Ebene_1"" xmlns=""http://www.w3.org/2000/svg"" xmlns:xlink=""http://www.w3.org/1999/xlink"" x=""0px"" y=""0px"" width=""560px"" height=""560px"" viewBox=""0 0 560 560"" xml:space=""preserve"">
<circle cx=""280.638"" cy=""279.639"" r=""250"" fill=""green""/>	
    <circle cx=""280.638"" cy=""279.639"" r=""27.719"" fill=""#CCCCCC""/>
    </svg>"));
        var canvas = Platforms.Current.CreateImageCanvas(svg.ViewBox.Size);

        //Re-Center for rotation
        var center = new NGraphics.Point(
            -svg.ViewBox.Size.Width / 2d, -svg.ViewBox.Size.Height / 2d);
        var centerTranslation = NGraphics.Transform.Translate(center);
        var movedSvg = svg.TransformGeometry(centerTranslation);

        //Rotation
        var angle = 20;
        var rotatedSvg = movedSvg.TransformGeometry(NGraphics.Transform.Rotate(angle));

        //Restore original position
        var ursprünglichePos = new NGraphics.Point(
            svg.ViewBox.Size.Width / 2d, svg.ViewBox.Size.Height / 2d);
        var reMovedTranslation = NGraphics.Transform.Translate(ursprünglichePos);
        var reMovedSvg = rotatedSvg.TransformGeometry(reMovedTranslation);

        //Draw
        reMovedSvg.Draw(canvas);

        //Resize
        var newSize = 250;
        var canvas2 = Platforms.Current.CreateImageCanvas(new NGraphics.Size(500));
        canvas2.DrawImage(canvas.GetImage(), new NGraphics.Rect(new NGraphics.Size(250)));

        //Output
        bitmap.Source = await (canvas2.GetImage() as NGraphics.WICBitmapSourceImage).SaveAsSoftwareBitmapSourceAsync();

Original Bug: yinyue200#1 (comment)

Linux Support

The Perspex project (https://github.com/grokys/Perspex/) are interested in maybe replacing our drawing abstractions with NGraphics, as it seems like you're doing a really good job! However, what do you think about Linux support? Linux is a platform we'd definitely like to support, however we're having a lot of troubles with Cairo.

Would you be interested in a Linux backend? Would it even be possible?

SVGReader path parser is extremely incomplete

I'm talking about this. The specs are here. There are a lot of issues

  • It assumes all commands/numbers are separated by commas or whitespace, which isn't true.

  • It assumes every command starts with a letter. This isn't necessarily true:

    "The command letter can be eliminated on subsequent commands if the same command is used multiple times in a row"

  • It doesn't support relative commands at all

  • It doesn't support H (horizontal line), V (vertical line), Q/T (quadratic curves)

  • Ellipse rotation is ignored (!?)

  • 'S' is not "continue curve", it's reflected curve.

Here is an example path which does not work. It draws the very simple Japanese character ノ (from KanjiVG)

M52.25,14c0.25,2.28-0.52,3.59-1.8,5.62c-5.76,9.14-17.9,27-39.2,39.88

UWP support

Would it be possible to add UWP support?

It seems that SharpDX 3 supports UWP.

Cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.