Signature Pad View does not contain getImage

I have use the Xamarin Control SignaturePad Form in my PCL project. The code as below:

    public class DigitalSignature : ContentPage
     {
            SignaturePadView sign = new SignaturePadView();

            public DigitalSignature()
            {
                Button btnOk = new Button
                {
                    Text = "Ok",
                    BackgroundColor = Color.FromHex("#ff6600"),
                    HorizontalOptions = LayoutOptions.End,
                    WidthRequest = 100,
                    HeightRequest = 35,
                    FontSize = 15
                };

                btnOk.Clicked += btnOk_Clicked;

                sign = new SignaturePadView()
                {
                    SignatureLineColor = Color.Red,
                    StrokeColor = Color.Black,
                    StrokeWidth = 10f,
                    HeightRequest = 150,
                    BackgroundColor = Color.White,
                    ClearText = "Clear Me"
                };
                sign.CaptionText = "pls sign here";


                Content = new StackLayout
                {
                    Children = {
                        sign,
                        btnOk
                    }
                };

            }

            private void btnOk_Clicked(object sender, EventArgs e)
            {

            }
        }

How I can get the signature as image and store in the database? In the signaturepadview do not has the getImage() function. Anyone has idea how I can do that?

Thanks,
Derick

Best Answer

Answers

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭
    edited January 2017

    Just a guess here...

    Bitmaps are different between platforms. An iOS bitmap is not the same as an Android bitmap. So you can't really have a PCL call to get that image. The documentation shows getting them as different types on the different OSes: One is a UIImage one is a Bitmap

    // on iOS:
    UIImage image = signature.GetImage ();
    
    // on Android:
    Bitmap image = signature.GetImage ();
    

    You'll probably need to make a tiny little DependencyService just to call the platform-specific version of GetImage. Maybe you could then normalize it to a Byte[] from each platform so the PCL gets the same kind of data from any platform. Then you can deal with it from there in a consistent way.

  • DerickLooDerickLoo USMember ✭✭

    Is that means I can't use the Xamarin.Controls.SignaturePad.Forms(SignaturePad.Forms.dll) control from the nuget and I should use the SignaturePad.dll and add in reference of each platform?

  • StephenGrahamStephenGraham GBMember ✭✭

    Hi DerickLoo,

    The SignaturePad (version 1.4.0) has a GetImageStreamAsync method that returns a stream in either PNG or JPG image format.

    I store my signatures as a binary array within a view model. To do this I convert the stream to a binary array using a BinaryReader. To view the stored signature I use an Image view.

    So my code looks something like this:-

    XAML code definition of SignaturePadView:-

              <!-- Signature -->
              <signature:SignaturePadView x:Name="signaturePad"
                                            BackgroundColor="White"
                                            CaptionText="{Binding Path=Signed,
                                                                  StringFormat={i18n:Translate Confirm_lblSigned}}"
                                            CaptionTextColor="Black"
                                            Grid.Row="2"
                                            PromptText="{Binding SignatureName,
                                                                 StringFormat={i18n:Translate Confirm_lblSignatureName}}"
                                            PromptTextColor="Black"
                                            SignatureLineColor="Black"
                                            StrokeColor="Black"/> 
    

    C# code in the code behind file converting from a stream to a binary array:-

                    // Save the signature before updating the database.
                    Stream image = await signaturePad.GetImageStreamAsync(SignatureImageFormat.Png);
                    // Write the signature to the orderheader.
                    using (BinaryReader binaryReader = new BinaryReader(image))
                    {
                        binaryReader.BaseStream.Position = 0;
                        orderHeader.Signature = binaryReader.ReadBytes((int)image.Length);
                    }
    

    View Model extract for signature storage:-

        public byte[] Signature {
            get
            {
                return signature;
            }
            set
            {
                SetProperty(ref signature, value);
            }
        }
    

    XAML code for bytetoimage converter:-

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            ...
                 xmlns:localConverter="clr-namespace:xxx.Converter">
    
      <ContentPage.Resources>
        <ResourceDictionary>
            ...
           <localConverter:ByteToImageConverter x:Key="byteToImage"/>
        </ResourceDictionary>
      </ContentPage.Resources>
    

    XAML code for image view used to display captured signature (used with a grid or stack layout in the body of your page):-

            <Image x:Name="imgSignature"
                   HorizontalOptions="Center"
                   Source="{Binding Signature, Converter={StaticResource byteToImage}}"
                   WidthRequest="200">
            </Image>
    

    And finally the C# code for the ByteToImage converter:-

            public class ByteToImageConverter : IValueConverter
            {
                public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
                {
                    ImageSource imageSource = null;
                    if (value != null)
                    {
                        byte[] image = (byte[])value;
                        imageSource = ImageSource.FromStream(() => new MemoryStream(image));
                    }
                    return imageSource;
                }
                public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
                {
                    throw new NotImplementedException();
                }
            }
    

    Hope this helps...

    SteveG

  • DerickLooDerickLoo USMember ✭✭

    Hi SteveG, may I know how I can store the image into database? Is it the byte value can be store into db?

  • StephenGrahamStephenGraham GBMember ✭✭

    Hi DerickLoo,

    I am using SQLite. I store the byte array into a BLOB (Binary Large Oject) in my database table.

    An extract of my table schema:-

    CREATE TABLE [OrderHeader] (
        Id int PRIMARY KEY NOT NULL,
        ...
        Signature BLOB NULL,
        ...);
    

    To get the data from my order header object (instantiated from a ViewModel holding the signature byte array) I create an SQLiteCommand object and execute an UPDATE statement as a non-query as follows:-

                    // Update the order header.
                    SQLiteCommand command = Connection.CreateCommand(
                        "UPDATE " +
                            "OrderHeader " +
                        "SET " +
                            "Signature = " +
                        "WHERE " +
                            "Id = ?",
                        orderHeader.Signature,
                        orderHeader.Id);
                    command.ExecuteNonQuery();
    

    The default maximum size for a BLOB in SQLite is 1 billion bytes, though you can change this if needed (see https://sqlite.org/limits.html). Although I have seen a few comments suggesting that BLOBs perform poorly and should be avoided, I am storing signatures around 8Kb in size with no noticeable degradation in performance. My test device is a Cubot S168.

    Hope this helps.

    SteveG

  • DerickLooDerickLoo USMember ✭✭

    Hi SteveG,
    I store the byte into MSSQL database and the datatype is Image. When I need display back the signature but it show me nothing, just a black color background. Below is the code I just do a testing, not get the byte data from database.

        Image iimg;
    
        public DigitalSignature()
        {
            Button btnOk = new Button
            {
                Text = "Ok",
                BackgroundColor = Color.FromHex("#ff6600"),
                HorizontalOptions = LayoutOptions.End,
                WidthRequest = 100,
                HeightRequest = 35,
                FontSize = 15
            };
    
            iimg = new Image
            {
                WidthRequest = 100,
                BackgroundColor = Color.Red
            };
    
            btnOk.Clicked += btnOk_Clicked;
    
            sign = new SignaturePadView()
            {
                SignatureLineColor = Color.Red,
                StrokeColor = Color.Black,
                StrokeWidth = 10f,
                HeightRequest = 150,
                BackgroundColor = Color.White,
                ClearText = "Clear Me"
            };
            sign.CaptionText = "pls sign here";
    
    
            Content = new StackLayout
            {
                Children = {
                    sign,
                    btnOk,
                    iimg
                }
            };
            //Content = sign;
        }
    
        private void btnOk_Clicked(object sender, EventArgs e)
        {        
            call();          
        }
    
        private async void call()
        {
            Stream img = await sign.GetImageStreamAsync(SignatureImageFormat.Jpg);
            BinaryReader br = new BinaryReader(img);
            br.BaseStream.Position = 0;
            Byte[] All = br.ReadBytes((int)img.Length);
    
            //display the signature
            byte[] image = (byte[])All;
            ImageSource imageSource = null;
            imageSource = ImageSource.FromStream(() => new MemoryStream(image));
            iimg.Source = imageSource;
    
        }
    

    Any mistake I make to render back the signature from the byte data.

  • DerickLooDerickLoo USMember ✭✭

    any one has an idea whats wrong for my code? Please Help

  • StephenGrahamStephenGraham GBMember ✭✭

    @DerickLoo said:
    any one has an idea whats wrong for my code? Please Help

    When you save your byte array to your MSSQL database best to use VARBINARY datatype because the Image data type has been deprecated for a few years. see http://stackoverflow.com/questions/444072/varbinary-vs-image-sql-server-data-type-to-store-binary-data

  • DerickLooDerickLoo USMember ✭✭

    @StephenGraham said:
    Change your image format from Jpg to Png. This change worked for me running on Android emulator (I haven't tested other platforms).

    Hi Stephen,
    Ya, I change the image format to Png and change the code where convert the signature to image as below. Now it work

    var img = await sign.GetImageStreamAsync(SignatureImageFormat.Png);
         var signatureMemoryStream = (MemoryStream)img;
         byte[] data = signatureMemoryStream.ToArray();
    

    Thanks for guiding me.

  • If I call the .GetImageStreamAsync(...) Method in a Xamarin UWP project I get the following error:

    System.TypeLoadException: 'Requested Windows Runtime type 'Microsoft.Graphics.Canvas.CanvasDevice' is not registered.'

    What to do?

  • mattleibowmattleibow ZAXamarin Team Xamurai

    Hi all, I just wanted to let you know about a major update to SignaturePad. You should now be able to get the latest (v2.0) on NuGet with all it's improvements: https://www.nuget.org/packages/Xamarin.Controls.SignaturePad.Forms/ and https://www.nuget.org/packages/Xamarin.Controls.SignaturePad/

    You can view release notes here: https://github.com/xamarin/SignaturePad/releases/tag/v2.0

    If you have any questions or suggestions, feel free to open issues. I will try and answer and address them as soon as possible.

  • dengerelidengereli TRMember ✭✭
    edited May 2017

    hello @mattleibow when I try SignaturePage in Xamarin.Forms
    image always null. I tried both of Jpeg or Png. I tested code on UWP.

            IFile file = await folder.CreateFileAsync("nuri.jpg", CreationCollisionOption.ReplaceExisting);
            Stream image = await PadView.GetImageStreamAsync(SignatureImageFormat.Jpeg);
            // Write the signature to the orderheader.
            using (BinaryReader binaryReader = new BinaryReader(image))
            {
                binaryReader.BaseStream.Position = 0;
                byte[] signature = binaryReader.ReadBytes((int)image.Length);
                using (var stream = await file.OpenAsync(FileAccess.ReadAndWrite))
                {
                    stream.Write(signature, 0, (int)image.Length);
                }
            }
    

    I'd like to save image to device storage....

  • mattleibowmattleibow ZAXamarin Team Xamurai

    @dengereli, unfortunately I was not able to reproduce the issue. I have created a simple sample here that works on UWP:

    https://github.com/mattleibow/SignaturePadDemo

    Make sure that you are using the latest version (or at least the same version) in all the projects - both the PCL (if you are using that) and the native app projects.

  • dengerelidengereli TRMember ✭✭

    @mattleibow nice sample thanks.

  • MatthiasBruzekMatthiasBruzek USMember ✭✭
    edited June 2017

    @MarkusHopfenspirger I have the same problem, did you find a solution or create an issue on github?

    Edit: Clean, delete bin/obj, rebuild worked for me.

  • MarkusHopfenspirgerMarkusHopfenspirger DEMember ✭✭
    edited June 2017

    @MatthiasBruzek I have not tried it since my question. But during the next weeks I will start working on this app again trying the new version and I can post my results here...

  • mattleibowmattleibow ZAXamarin Team Xamurai
    edited June 2017

    @MarkusHopfenspirger I also got that issue and I found that I had forgotten to install the Win2D packages into my app projects. They should be installed when you install SignaturePad, but I had been fiddling around - so just check that you have it installed. and then follow @MatthiasBrckner for good measure :)

  • MarkusHopfenspirgerMarkusHopfenspirger DEMember ✭✭

    For me this did not help. I also installed the Win2D package manually and tried other things like this without success... But I will see with the new version. I just have to finish my current project first...

  • mattleibowmattleibow ZAXamarin Team Xamurai

    What device was this?

  • MarkusHopfenspirgerMarkusHopfenspirger DEMember ✭✭

    It was my lokal Windows 10 Laptop and my Lumia 950 XL.

  • Seddy24Seddy24 Member

    Anyone have a working MVVM example? I would prefer to not have any code in the content page to retrieve the image.

Sign In or Register to comment.