Open xyashapyx opened 7 years ago
I have this problem too. It would be really helpful if you could add a boolean property 'IncludeBackgroundImage' to the ImageConstructionSettings, so it can be backwards compatible.
A feature to get the drawn component and the background as a single image is something that I would like to use as well. Would such a feature be considered to be added to SignaturePad?
I'd like to see this implemented as well.
It would be awesome indeed,
I currently 'extended' the signaturepad view as follows:
Forms View
public class MarkingView : SignaturePadView
{
public Func<string> SaveImageWithBackground;
}
IOS Renderer
[assembly: ExportRenderer (typeof(MarkingView), typeof(MarkingViewRenderer))]
namespace B2B.iOS
{
public class MarkingViewRenderer : ViewRenderer<MarkingView, SignaturePadView>
{
protected override void OnElementChanged(ElementChangedEventArgs<MarkingView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
e.OldElement.SaveImageWithBackground = null;
}
if (e.NewElement != null)
{
e.NewElement.SaveImageWithBackground += NewElement_SaveImageWithBackground;
}
}
string NewElement_SaveImageWithBackground()
{
UIGraphics.BeginImageContextWithOptions(Bounds.Size, false, 0f);
using(var context = UIGraphics.GetCurrentContext())
{
Layer.RenderInContext(context);
using (UIImage img = UIGraphics.GetImageFromCurrentImageContext())
{
UIGraphics.EndImageContext();
string folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string filename;
do
{
filename = Path.Combine(folder, "Marking-" + DateTime.Now.Ticks + ".png");
}
while (File.Exists(filename));
img.AsPNG().Save(filename, true);
return filename;
}
}
}
}
}
Android Renderer
[assembly: ExportRenderer (typeof(MarkingView), typeof(MarkingViewRenderer))]
namespace B2B.Droid
{
public class MarkingViewRenderer : ViewRenderer<MarkingView, SignaturePadView>
{
protected override void OnElementChanged (ElementChangedEventArgs<MarkingView> e)
{
base.OnElementChanged (e);
if (e.OldElement != null) {
e.OldElement.SaveImageWithBackground = null;
}
if (e.NewElement != null) {
e.NewElement.SaveImageWithBackground += NewElement_SaveImageWithBackground;
}
}
string NewElement_SaveImageWithBackground()
{
using(Bitmap bm = Bitmap.CreateBitmap(Width, Height, Bitmap.Config.Argb8888))
{
using(Canvas canvas = new Canvas(bm))
{
Drawable bgDrawable = Background;
if (bgDrawable != null)
{
bgDrawable.Draw(canvas);
}
Draw(canvas);
string folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string filename;
do
{
filename = System.IO.Path.Combine(folder, "Marking-" + DateTime.Now.Ticks + ".png");
}
while (File.Exists(filename));
using (var fs = new System.IO.FileStream(filename, FileMode.CreateNew))
{
bm.Compress(Bitmap.CompressFormat.Png, 90, fs);
bm.Recycle();
return filename;
}
}
}
}
}
}
Feel free to use it. It's not perfect, but it works for my needs
This seems to be a popular request, we will put this on the list of things to do for a future release.
Vandersteen what are the using statements from your renderer classes? I get the following errors for the class definition line -
The type 'SignaturePad.Forms.SignaturePadView' cannot be used as type parameter 'TNativeView' in the generic type or method 'ViewRenderer<TView, TNativeView>'. There is no implicit reference conversion from 'SignaturePad.Forms.SignaturePadView' to 'UIKit.UIView'. & The type 'SignaturePad.Forms.SignaturePadView' cannot be used as type parameter 'TNativeView' in the generic type or method 'ViewRenderer<TView, TNativeView>'. There is no implicit reference conversion from 'SignaturePad.Forms.SignaturePadView' to 'Android.Views.View'.
IOS:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using UIKit;
using System.IO;
using Xamarin.Controls;
//our shared app namespace
//our native app namespace
Android:
using System;
using Xamarin.Forms;
using System.IO;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;
using Xamarin.Controls;
using Android.Graphics.Drawables;
//our shared app namespace
//our native app namespace
Vandersteen thats a great renderer, well done. You can make a basic image editor from that. Do you have any idea if you can get rid extra part the signature pad adds to the background image for the signature line? I can make it transparent but its still on the image when i save it? any ideas? I was also wondering if you could add another image on top of the background image like a sticker using that renderer?
I did not test it but I think you could do the following:
//Replace
Layer.RenderInContext(context);
//With
Control.BackgroundImageView.Layer.RenderInContext(context);
Control.SignatureLine.Layer.RenderInContext(context);
Same thing for android:
//Replace
Draw(canvas);
//With
Control.BackgroundImageView.Draw(canvas);
Control.SignatureLine.Draw(canvas);
var watermark = new UIImageView(); ... watermark.Layer.RenderInContext(context);
Again, not tested, but that's where I would start
Vandersteen NICE GOING! What you have developed is exactly what I need now. I have tried to implement it, but getting errors. Would it be possible for you to post a sample code of your render implementation?
I posted the renderers above.
For the view usage you will just need to do the following:
var markingView = new MarkingView(); ... var pathToImage = markingView. SaveImageWithBackground();
Vandersteen - thank you for the post. I implemented your code, but many problems arise and I cannot compile. I must be doing something wrong. Here is my code:
`using System;
using Xamarin.Forms;
using System.IO;
using Xamarin.Forms.Platform.Android;
using Android.Graphics;
using Xamarin.Controls;
using Android.Graphics.Drawables;
using ES;
using ES.Droid;
//our native app namespace
[assembly: ExportRenderer(typeof(MarkingView), typeof(MarkingViewRenderer))]
namespace ES.Droid
{
public class MarkingView : SignaturePadView
{
public Func
public class MarkingViewRenderer : ViewRenderer<MarkingView, SignaturePadView>
{
protected override void OnElementChanged(ElementChangedEventArgs<MarkingView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
e.OldElement.SaveImageWithBackground = null;
}
if (e.NewElement != null)
{
e.NewElement.SaveImageWithBackground += NewElement_SaveImageWithBackground;
}
}
private string NewElement_SaveImageWithBackground()
{
using (Bitmap bm = Bitmap.CreateBitmap(Width, Height, Bitmap.Config.Argb8888))
{
using (Canvas canvas = new Canvas(bm))
{
Drawable bgDrawable = Background;
if (bgDrawable != null)
{
bgDrawable.Draw(canvas);
}
Draw(canvas);
string folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string filename;
do
{
filename = System.IO.Path.Combine(folder, "Marking-" + DateTime.Now.Ticks + ".png");
}
while (File.Exists(filename));
using (var fs = new FileStream(filename, FileMode.CreateNew))
{
bm.Compress(Bitmap.CompressFormat.Png, 90, fs);
bm.Recycle();
return filename;
}
}
}
}
}
}`
Here are the errors:
Severity Code Description Project File Line Suppression State Error CS0311 The type 'ES.Droid.MarkingView' cannot be used as type parameter 'TView' in the generic type or method 'ViewRenderer<TView, TNativeView>'. There is no implicit reference conversion from 'ES.Droid.MarkingView' to 'Xamarin.Forms.View'. EnSpect.Android C:\J\Software\ES\ES\ES.Android\MarkingView.cs 20 Active
Severity Code Description Project File Line Suppression State Error CS0311 The type 'ES.Droid.MarkingView' cannot be used as type parameter 'TElement' in the generic type or method 'ElementChangedEventArgs<TElement>'. There is no implicit reference conversion from 'ES.Droid.MarkingView' to 'Xamarin.Forms.Element'. ES.Android C:\J\Software\ES\ES\ES.Android\MarkingView.cs 22 Active
Severity Code Description Project File Line Suppression State Error CS1729 'SignaturePadView' does not contain a constructor that takes 0 arguments ES.Android C:\J\Software\ES\ES\ES.Android\MarkingView.cs 14 Active
Any suggestions how to fix?
This needs a bit more thought - same with other "chrome" features, similar to https://github.com/xamarin/SignaturePad/issues/127
I actually used the example of @Vandersteen to implement the signaturepad to allow us to annotate images. I know this component is meant for recording signatures, but we use it to let people annotate images they just selected or pictures they just took to clarify a photo of a situation. This works perfectly. Support built into the package would be great, because it would mean less code to maintain on our end.
I would love to see this implemented as well. It would be really helpful. Thanks
@Vandersteen very nice solution! However, I would want to pass an argument to the function such that I can save it to a specific directory. Could you help me extend the function for an additional parameter that I can pass into the SaveImageWithBackground
function.
Something like:
signPad.SaveImageWithBackground(“something”);
I extended @Vandersteen's example by taking one more argument, such that I can pass in the directory where to save the files to. In my case, I want to save them in a specific directory for each signature:
public class CustomSignaturePadView : SignaturePadView
{
public Func<string, string> SaveImageWithBackground;
}
And then you only need to extend the NewElement_SaveImageWithBackground
functions by one parameter, like so string NewElement_SaveImageWithBackground(string path)
.
If you are setting BackgroundImage and draw on it, only drawn part will be returned, not BackgroundImage with drawings.