poner pie mail insertar imagenes imagen firma electronica correo con como ios xamarin.ios core-graphics electronic-signature
https://dl.dropboxusercontent.com/u/25670071/SignatureArchive.zip

pie - Problema de rendimiento al capturar la firma en iOS



insertar imagen en firma mail iphone (4)

Tengo un control de firma que funciona muy bien, excepto si tienes un nombre largo, entonces comienza a mostrar espacios vacíos. Parece estar relacionado con el rendimiento, pero es el mismo tanto en el simulador como en el último iPad. He adjuntado un proyecto de muestra a continuación junto con el código de dibujo de la firma.

¡Cualquier ayuda será muy apreciada!

https://dl.dropboxusercontent.com/u/25670071/SignatureArchive.zip

using System; using MonoTouch.UIKit; using MonoTouch.CoreGraphics; using System.Drawing; namespace MyApp { public class SignatureViewV2 : UIView { public delegate void SignatureChanged(); public SignatureChanged OnSignatureChanged; private bool _empty = true; // clear the canvas public void Clear () { drawPath.Dispose (); drawPath = new CGPath (); fingerDraw = false; SetNeedsDisplay (); _empty = true; } public bool IsEmpty () { return _empty; } public SignatureViewV2 (RectangleF frame) : base(frame) { this.drawPath = new CGPath (); this.BackgroundColor = UIColor.White; } private PointF touchLocation; private PointF prevTouchLocation; private CGPath drawPath; private bool fingerDraw; public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt) { base.TouchesBegan (touches, evt); UITouch touch = touches.AnyObject as UITouch; this.fingerDraw = true; this.touchLocation = touch.LocationInView (this); this.prevTouchLocation = touch.PreviousLocationInView (this); this.SetNeedsDisplay (); } public override void Draw (RectangleF rect) { base.Draw (rect); if (this.fingerDraw) { using (CGContext context = UIGraphics.GetCurrentContext()) { context.SetStrokeColor (UIColor.FromRGB(63, 112, 185).CGColor); context.SetLineWidth (2f); context.SetLineJoin (CGLineJoin.Round); context.SetLineCap (CGLineCap.Round); this.drawPath.MoveToPoint (this.prevTouchLocation); this.drawPath.AddLineToPoint (this.touchLocation); context.AddPath (this.drawPath); context.DrawPath (CGPathDrawingMode.Stroke); } if(OnSignatureChanged != null) OnSignatureChanged(); _empty = false; } } public override void TouchesMoved (MonoTouch.Foundation.NSSet touches, UIEvent evt) { base.TouchesMoved (touches, evt); UITouch touch = touches.AnyObject as UITouch; this.touchLocation = touch.LocationInView (this); this.prevTouchLocation = touch.PreviousLocationInView (this); this.SetNeedsDisplay (); } public UIImage GetDrawingImage () { UIImage returnImg = null; UIGraphics.BeginImageContext (this.Bounds.Size); using (CGContext context = UIGraphics.GetCurrentContext()) { context.SetStrokeColor (UIColor.FromRGB(63, 112, 185).CGColor); context.SetLineWidth (5f); context.SetLineJoin (CGLineJoin.Round); context.SetLineCap (CGLineCap.Round); context.AddPath (this.drawPath); context.DrawPath (CGPathDrawingMode.Stroke); returnImg = UIGraphics.GetImageFromCurrentImageContext (); } UIGraphics.EndImageContext (); return returnImg; } }

}


Después de haber probado todas las respuestas, decidí convertir un ejemplo de Object-c utilizando curvas Bezier que proporcionaron una firma mucho más agradable en mi opinión. Este código está tomado de esta excelente publicación sobre el tema: http://mobile.tutsplus.com/tutorials/iphone/ios-sdk_freehand-drawing/

public class SignatureViewV3 : UIView { public delegate void SignatureChanged (); public SignatureChanged OnSignatureChanged; private bool _empty = true; UIBezierPath path; UIImage incrementalImage; PointF[] pts = new PointF[5]; uint ctr; [Export ("initWithFrame:")] public SignatureViewV3 (RectangleF rect): base(rect) { this.MultipleTouchEnabled = false; this.BackgroundColor = UIColor.Clear; path = new UIBezierPath(); path.LineWidth = 2; } public bool IsEmpty() { return incrementalImage == null && ctr == 0; } public void Clear() { if(incrementalImage != null) { incrementalImage.Dispose (); incrementalImage = null; } path.RemoveAllPoints (); SetNeedsDisplay (); } [Export("initWithCoder:")] public SignatureViewV3 (NSCoder coder) : base(coder) { this.MultipleTouchEnabled = false; this.BackgroundColor = UIColor.Clear; path = new UIBezierPath(); path.LineWidth = 2; } public override void Draw (RectangleF rect) { if (incrementalImage != null) incrementalImage.Draw(rect); path.Stroke(); } public override void TouchesBegan (NSSet touches, UIEvent evt) { ctr = 0; UITouch touch = touches.AnyObject as UITouch; pts[0] = touch.LocationInView(this); } public override void TouchesMoved (NSSet touches, UIEvent evt) { if(OnSignatureChanged != null) OnSignatureChanged (); UITouch touch = touches.AnyObject as UITouch; PointF p = touch.LocationInView(this); ctr++; pts[ctr] = p; if (ctr == 3) { pts[2] = new PointF((pts[1].X + pts[3].X)/2.0f, (pts[1].Y + pts[3].Y)/2.0f); path.MoveTo(pts[0]); path.AddQuadCurveToPoint (pts [2], pts [1]); this.SetNeedsDisplay (); pts[0] = pts[2]; pts[1] = pts[3]; ctr = 1; } } public override void TouchesEnded (NSSet touches, UIEvent evt) { if (ctr == 0) // only one point acquired = user tapped on the screen { path.AddArc (pts [0], path.LineWidth / 2, 0, (float)(Math.PI * 2), true); } else if (ctr == 1) { path.MoveTo (pts [0]); path.AddLineTo (pts [1]); } else if (ctr == 2) { path.MoveTo (pts [0]); path.AddQuadCurveToPoint (pts [2], pts [1]); } this.drawBitmap(); this.SetNeedsDisplay(); path.RemoveAllPoints(); ctr = 0; } public override void TouchesCancelled (NSSet touches, UIEvent evt) { this.TouchesEnded(touches, evt); } public UIImage GetDrawingImage () { UIGraphics.BeginImageContextWithOptions(this.Bounds.Size, false, 0); if(incrementalImage == null) { incrementalImage = new UIImage (); UIBezierPath rectPath = UIBezierPath.FromRect(this.Bounds); UIColor.Clear.SetFill(); rectPath.Fill(); } incrementalImage.Draw(new PointF(0,0)); UIColor.Black.SetStroke(); path.Stroke(); incrementalImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); return incrementalImage; } public void drawBitmap() { UIGraphics.BeginImageContextWithOptions(this.Bounds.Size, false, 0); if(incrementalImage == null) { incrementalImage = new UIImage (); UIBezierPath rectPath = UIBezierPath.FromRect(this.Bounds); UIColor.Clear.SetFill(); rectPath.Fill(); } incrementalImage.Draw(new PointF(0,0)); UIColor.Black.SetStroke(); path.Stroke(); incrementalImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); } }


He tenido exactamente el mismo problema descrito en la pregunta. Miré la respuesta de @Dmitry anterior, pero era bastante diferente de la que tengo y requeriría muchos cambios. así que seguí el consejo de @Stephane anterior y acabo de hacer las colas de MoveTouches, que funcionó perfectamente. Gracias chicos.

Estoy poniendo mi solución aquí en caso de que alguien más la necesite. Tenga en cuenta que estoy capturando los puntos distintivos, no la firma como una imagen. Tenemos otro algorithem para renderizar estos puntos usando diferentes configuraciones

using MonoTouch.CoreGraphics; using MonoTouch.UIKit; using System.Drawing; using System; using Leopard.Interfaces; using MonoTouch.Foundation; using Leopard.Mobile.Core.Signature; using Leopard.Mobile.Core.Drawing; using Leopard.Interfaces.Drawing; using Leopard.Interfaces.Screens.Controls; using System.Linq; using System.Collections.Concurrent; namespace Leopard.Mobile.Controls { public class SignatureView : LeopardControlBase, ISignatureView { public SignatureView (RectangleF frame) : base(frame) { base.Frame = frame; ViewFrame = new LeopardFrame { X = (int)frame.X, Y = (int) frame.Y, Width = frame.Width, Height = frame.Height }; _DrawPath = new CGPath(); SetupAppearance(); _ScalingFactor = new LeopardFrame { Width = 1, Height = 1 }; DrawWatermarks(); } public void Initialise(int penWidth, WatermarkSettings watermarks, string backgroundImageFileName) { PenWidth = penWidth; Watermarks = watermarks; BackgroundImageFileName = backgroundImageFileName; var dimensions = new LeopardFrame { Width = Frame.Width, Height = Frame.Height }; _SignatureData = new SignatureData(dimensions, _ScalingFactor, watermarks); } public void Clear () { _DrawPath.Dispose(); _DrawPath = new CGPath(); _FingerDraw = false; _TouchLocation = new PointF(0, 0); _PrevTouchLocation = new PointF(0, 0); SetNeedsDisplay(); _SignatureData.Clear(); DrawWatermarks(); _TouchsQueue = new ConcurrentQueue<TouchsQueue>(); } public override void TouchesBegan(NSSet touches, UIEvent evt) { base.TouchesBegan (touches, evt); UITouch touch = touches.AnyObject as UITouch; this._FingerDraw = true; this._TouchLocation = touch.LocationInView (this); this._PrevTouchLocation = touch.PreviousLocationInView (this); this.SetNeedsDisplay (); _SignatureData.AddPoint(SignatureState.Start, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); } public override void TouchesEnded(NSSet touches, UIEvent e) { base.TouchesEnded(touches, e); if (this._FingerDraw) { UITouch touch = touches.AnyObject as UITouch; _TouchLocation = touch.LocationInView(this); _PrevTouchLocation = touch.PreviousLocationInView(this); _FingerDraw = false; _SignatureData.AddPoint(SignatureState.End, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); } } public override void TouchesMoved (NSSet touches, UIEvent evt) { base.TouchesMoved (touches, evt); UITouch touch = touches.AnyObject as UITouch; _TouchLocation = touch.LocationInView(this); _PrevTouchLocation = touch.PreviousLocationInView(this); _TouchsQueue.Enqueue(new TouchsQueue {TouchLocation = _TouchLocation, PrevTouchLocation = _PrevTouchLocation }); _SignatureData.AddPoint(SignatureState.Move, (int)this._TouchLocation.X, (int)this._TouchLocation.Y); SetNeedsDisplay(); } public override void Draw (RectangleF rect) { base.Draw (rect); if (_DrawPath != null) { using (CGContext context = UIGraphics.GetCurrentContext()) { if (context != null) { DrawSignatureLines(context); } } } } private void DrawSignatureLines(CGContext context) { TouchsQueue queueElement = null; while(_TouchsQueue.TryDequeue(out queueElement)) { if (queueElement != null) { context.SetStrokeColor(UIColor.Black.CGColor); context.SetLineWidth(PenWidth); context.SetLineJoin(CGLineJoin.Round); context.SetLineCap(CGLineCap.Round); _DrawPath.MoveToPoint(queueElement.PrevTouchLocation); _DrawPath.AddLineToPoint(queueElement.TouchLocation); context.AddPath(_DrawPath); context.DrawPath(CGPathDrawingMode.Stroke); } } } public void Add(IControl control) { var view = control as UIView; if (view != null) { EnsureAddingWatermarkControl(view); } } public string GetSignatureData() { var result = string.Empty; if (_SignatureData != null) { try { result = _SignatureData.ExtractAsString(); } catch (Exception exception) { OnFailedWithException(exception); } } return result; } #region Implementation private PointF _TouchLocation; private PointF _PrevTouchLocation; private CGPath _DrawPath; private bool _FingerDraw; private ConcurrentQueue<TouchsQueue> _TouchsQueue = new ConcurrentQueue<TouchsQueue>(); private ILeopardFrame _ScalingFactor; private SignatureData _SignatureData { get; set; } public SignatureData SignatureData { get { return _SignatureData; } } public event SignatureFailedWithExceptionHandler SignatureFailedWithException; public string BackgroundImageFileName {get;set;} public int PenWidth { get; set; } public WatermarkSettings Watermarks {get;set;} public ILeopardFrame ViewFrame { get; set; } private void OnFailedWithException(Exception exception) { if (SignatureFailedWithException != null) { SignatureFailedWithException(exception); } } private void EnsureAddingWatermarkControl(UIView view) { var existingView = this.Subviews.ToList().FirstOrDefault( v => v is IControl && v.Frame.X == view.Frame.X && v.Frame.Y == view.Frame.Y); if (existingView != null) { existingView.RemoveFromSuperview(); existingView.Dispose(); } this.AddSubview(view); } private void DrawWatermarks() { if (Watermarks != null) { Watermarks.DrawWatermarks(this, _ScalingFactor); } } private void SetupAppearance () { BackgroundColor = UIColor.White; Layer.BorderWidth = 5f; Layer.BorderColor = UIColor.FromRGB ( Constants.LeopardBackgroundColors.Red, Constants.LeopardBackgroundColors.Green, Constants.LeopardBackgroundColors.Blue ).CGColor; } #endregion } public class TouchsQueue { public PointF TouchLocation {get;set;} public PointF PrevTouchLocation { get; set; } }

}


Me he encontrado con el mismo problema una vez que algunos de los usuarios de la aplicación interna se actualizaron a iOS 7. Intenté utilizar una curva Queue y Bezier en lugar de conectar los puntos de contacto, pero al final cambié al uso de OpenGL en mi implementación.

He encontrado una guía bastante útil aquí: Capture a Signature en iOS y el proyecto Objective-C en Github: Signature Demo

Me llevó un día reescribirlo en C # y adaptarlo para su uso en mi aplicación, ya que no soy tan bueno en Obj-C, pero funciona bastante bien.

El código de clase está disponible aquí (clase GLSignatureView): Github


No puede confiar en que se llame a Draw() para cada TouchesMoved() . Si se llama a Draw() cada 2 toques, se obtienen espacios como los descritos.

Resolvería eso haciendo cola (por ejemplo, en una Queue<T> ) los toques en TouchesMoved() y dequeuing en Draw()

También podría tener otro problema: en cada Draw() , está volviendo a agregar la ruta completa a la ruta actual cada vez. Probablemente pueda resolver esto llamando solo a AddPath para el nuevo segmento o llamando a AddPath() una vez, agregando segmentos a su ruta (`Move, AddLine) y redibujándolo. Pero no he probado nada de esto.