Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write a shape file in Xamarin.forms bug #51

Open
benabdelkrim opened this issue Nov 5, 2020 · 19 comments
Open

Write a shape file in Xamarin.forms bug #51

benabdelkrim opened this issue Nov 5, 2020 · 19 comments
Assignees
Labels
bug Something isn't working waiting for feedback

Comments

@benabdelkrim
Copy link

exception

@DGuidi
Copy link
Contributor

DGuidi commented Nov 5, 2020

please post the complete code you're testing, from this I don't see why the line highlighted can throw a "ArgumentNullException" actually. No similar "throws" in the source code

I suspect the error is in attributes dictionary...

@benabdelkrim
Copy link
Author

capturebug

@FObermaier
Copy link
Member

Posting images of your VisualStudio instance is not useful.
Please set up a minimum working sample project for us to test your code.

@benabdelkrim
Copy link
Author

string path;
string C_postal = "C_postal";
string Type_bat = "Type_bat";
string X_coord = "X_coord";
string Y_coord = "Y_coord";
//create geometry factory
GeometryFactory geomFactory = NtsGeometryServices.Instance.CreateGeometryFactory();
//create the default table with fields - alternately use DBaseField classes
AttributesTable attributes1 = new AttributesTable();
attributes1.Add(C_postal, "40050");
attributes1.Add(Type_bat, "Immeuble");
attributes1.Add(X_coord, "300000");
attributes1.Add(Y_coord, "5000000");
AttributesTable attributes2 = new AttributesTable();
attributes2.Add(C_postal, "40050");
attributes2.Add(Type_bat, "Using");
attributes2.Add(X_coord, "300200");
attributes2.Add(Y_coord, "5000300");
//create geometries and features
Geometry geometry1 = geomFactory.CreatePoint(new Coordinate(300000, 5000000));
Geometry geometry2 = geomFactory.CreatePoint(new Coordinate(300200, 5000300));
Feature feat1 = new Feature(geometry1, attributes1);
Feature feat2 = new Feature(geometry2, attributes2);
//create attribute list
IList features = new List() { feat1, feat2 };
path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shape");
ShapefileDataWriter writer = new ShapefileDataWriter(path);
writer.Header = ShapefileDataWriter.GetHeader(features[0], features.Count);
System.Collections.IList featList = (System.Collections.IList)features;
writer.Write(features);

@DGuidi DGuidi self-assigned this Nov 5, 2020
@DGuidi DGuidi added the question Further information is requested label Nov 5, 2020
@benabdelkrim
Copy link
Author

this code is working in application desktop c# but in Xamarin.forms not working, i don't know why ?

@FObermaier
Copy link
Member

I'm still missing a project file, the code you posted is just a function. Now, to get to where you are at, we do have to put in effort to set up a project that uses Xamairn.Forms, that eventually invokes your code. Please provide a minimum working sample project for us to test your code.

@benabdelkrim
Copy link
Author

thank you for find the code in this link
https://www.swisstransfer.com/d/c1fda1a0-e909-4d7f-a992-e86e0970d66f

@DGuidi
Copy link
Contributor

DGuidi commented Nov 5, 2020

this code works in .net, I made small changes

string path;
            string C_postal = "C_postal";
            string Type_bat = "Type_bat";
            string X_coord = "X_coord";
            string Y_coord = "Y_coord";
            //create geometry factory
            var geomFactory = NtsGeometryServices.Instance.CreateGeometryFactory();
            //create the default table with fields - alternately use DBaseField classes
            var attributes1 = new AttributesTable();
            attributes1.Add(C_postal, "40050");
            attributes1.Add(Type_bat, "Immeuble");
            attributes1.Add(X_coord, "300000");
            attributes1.Add(Y_coord, "5000000");
            var attributes2 = new AttributesTable();
            attributes2.Add(C_postal, "40050");
            attributes2.Add(Type_bat, "Using");
            attributes2.Add(X_coord, "300200");
            attributes2.Add(Y_coord, "5000300");
            //create geometries and features
            Geometry geometry1 = geomFactory.CreatePoint(new Coordinate(300000, 5000000));
            Geometry geometry2 = geomFactory.CreatePoint(new Coordinate(300200, 5000300));
            var feat1 = new Feature(geometry1, attributes1);
            var feat2 = new Feature(geometry2, attributes2);
            //create attribute list
            var features = new List<IFeature>() { feat1, feat2 };
            path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "shape");
            var writer = new ShapefileDataWriter(path);
            writer.Header = ShapefileDataWriter.GetHeader(features[0], features.Count);
            writer.Write(features);

@benabdelkrim
Copy link
Author

it still the problem ! even i separate the Header !
var writer = new ShapefileDataWriter(path);
writer.Header = ShapefileDataWriter.GetHeader(features[0], features.Count);
Other thing this code is working in .NET but in xamarin.forms i have this problem

@DGuidi
Copy link
Contributor

DGuidi commented Nov 5, 2020

can you post the stack trace? can be helpful to investigate what is the method actually throwing the exception

@FObermaier
Copy link
Member

The cause for this to fail is probably the failure of the initialization of NetTopologySuite.IO.DbaseEncodingUtility.
Maybe some of the initial codepages are not available for Android?

@FObermaier FObermaier added the bug Something isn't working label Nov 5, 2020
@benabdelkrim
Copy link
Author

Please I need to know if there's a solution to read/write a shapefile in Xamarin.forms. I really appreciate your help.

Thanks in advance.

@DGuidi
Copy link
Contributor

DGuidi commented Nov 5, 2020

oh, understood. Maybe you can try to initialize the writer using an explicit Encoding as the third parameter and see if it works

new ShapefileDataWriter(path, geomFactory, Encoding.UTF8) // or ASCII

BTW I'm trying to install Xamarin to do some tests... but it takes quite a time! Abd it's incredibly slow without Hyper-V acceleration (unavailable in my system...)

@DGuidi
Copy link
Contributor

DGuidi commented Nov 6, 2020

@FObermaier GetEncodingForCodePageIdentifier(437) - French OEM - returns null
this code shall work but actually the write of the features fail...

ShapefileDataWriter writer = new ShapefileDataWriter(path, geomFactory, Encoding.Default);
writer.Header = ShapefileDataWriter.GetHeader(features[0], features.Count, Encoding.Default);
writer.Write(features);

because RegisterEncodings stops recording all the other encodings after the first that fails, I think...
handling all the exceptions, and not only NotSupportedException, fix the problem

try
{
  var enc = GetEncodingForCodePageIdentifier(codePage);
  AddLdidEncodingPair(ldid, enc);
}
catch //(NotSupportedException)
{
  string message = string.Format("Failed to get codepage for language driver {0}", ldid);
  Debug.WriteLine(message);
}

those are the missing encodings

Loaded assembly: System.Text.Encoding.CodePages.dll [External]
[0:] Failed to get codepage for language driver 1
[0:] Failed to get codepage for language driver 2
[0:] Failed to get codepage for language driver 8
[0:] Failed to get codepage for language driver 9
[0:] Failed to get codepage for language driver 10
[0:] Failed to get codepage for language driver 11
[0:] Failed to get codepage for language driver 13
[0:] Failed to get codepage for language driver 14
[0:] Failed to get codepage for language driver 15
[0:] Failed to get codepage for language driver 16
[0:] Failed to get codepage for language driver 17
[0:] Failed to get codepage for language driver 18
[0:] Failed to get codepage for language driver 19
[0:] Failed to get codepage for language driver 20
[0:] Failed to get codepage for language driver 21
[0:] Failed to get codepage for language driver 22
[0:] Failed to get codepage for language driver 23
[0:] Failed to get codepage for language driver 24
[0:] Failed to get codepage for language driver 25
[0:] Failed to get codepage for language driver 26
[0:] Failed to get codepage for language driver 27
[0:] Failed to get codepage for language driver 28
[0:] Failed to get codepage for language driver 29
[0:] Failed to get codepage for language driver 31
[0:] Failed to get codepage for language driver 34
[0:] Failed to get codepage for language driver 35
[0:] Failed to get codepage for language driver 36
[0:] Failed to get codepage for language driver 37
[0:] Failed to get codepage for language driver 38
[0:] Failed to get codepage for language driver 55
[0:] Failed to get codepage for language driver 64
[0:] Failed to get codepage for language driver 77
[0:] Failed to get codepage for language driver 78
[0:] Failed to get codepage for language driver 79
[0:] Failed to get codepage for language driver 80
[0:] Failed to get codepage for language driver 88
[0:] Failed to get codepage for language driver 89
[0:] Failed to get codepage for language driver 100
[0:] Failed to get codepage for language driver 101
[0:] Failed to get codepage for language driver 102
[0:] Failed to get codepage for language driver 103
[0:] Failed to get codepage for language driver 106
[0:] Failed to get codepage for language driver 107
[0:] Failed to get codepage for language driver 108
[0:] Failed to get codepage for language driver 120
[0:] Failed to get codepage for language driver 121
[0:] Failed to get codepage for language driver 122
[0:] Failed to get codepage for language driver 123
[0:] Failed to get codepage for language driver 124
[0:] Failed to get codepage for language driver 134
[0:] Failed to get codepage for language driver 135
[0:] Failed to get codepage for language driver 136
[0:] Failed to get codepage for language driver 200
[0:] Failed to get codepage for language driver 201
[0:] Failed to get codepage for language driver 202
[0:] Failed to get codepage for language driver 203
[0:] Failed to get codepage for language driver 204

@FObermaier if you agree I can push the fix direclty from my side, let me know

@DGuidi
Copy link
Contributor

DGuidi commented Nov 6, 2020

@benabdelkrim you can do this to continue working

  1. checkout nettopologysuite.io.shapefile code
  2. add the nts.io.shapefile project to your solution
  3. remove the nuget reference to nts.io.shapefile and add the project reference
  4. patch the DBaseEncodingUtility.RegisterEncodings in nts.io.shapefile as:
try
{
  var enc = GetEncodingForCodePageIdentifier(codePage);
  AddLdidEncodingPair(ldid, enc);
}
catch //(NotSupportedException)
{
  string message = string.Format("Failed to get codepage for language driver {0}", ldid);
  Debug.WriteLine(message);
}
  1. use this code
ShapefileDataWriter writer = new ShapefileDataWriter(path, geomFactory, Encoding.Default);
writer.Header = ShapefileDataWriter.GetHeader(features[0], features.Count, Encoding.Default);
writer.Write(features);

@FObermaier
Copy link
Member

FObermaier commented Nov 6, 2020

@DGuidi current implementation of GetEncodingForCodePageIdentifier(int) does not work well on Android.
Changing the implementation to

/// <summary>
/// Utility function to get an encoding for the provided codepage identifier
/// </summary>
/// <param name="codePage">A code page identifier</param>
/// <returns> An <c>Encoding</c> or <c>null</c></returns>
public static Encoding GetEncodingForCodePageIdentifier(int codePage)
{
    try { return CodePagesEncodingProvider.Instance.GetEncoding(codePage) ?? Encoding.GetEncoding(codePage); }
    catch { return null; }
}

gives much better results. No Encoding that can't be found. I changed the implementation of RegisterEncodings to

private static void RegisterEncodings(object[][] ldidCodePagePairs)
{
    var validCodePages = new HashSet<int>(Encoding.GetEncodings().Select(t => t.CodePage));
    foreach (object[] ldidCodePagePair in ldidCodePagePairs)
    {
        byte ldid = Convert.ToByte(ldidCodePagePair[0], CultureInfo.InvariantCulture);
        int codePage = (int)ldidCodePagePair[1];
        if (validCodePages.Contains(codePage))
            AddLdidEncodingPair(ldid, Encoding.GetEncoding(codePage));
#if DEBUG
        else
        {
            Debug.WriteLine("Failed to get Encoding for ldid={0} (Codepage {1})", ldid, codePage);
        }
#endif
    }
}

Additionally I made the the unit tests pass, there were a lot failing...
If you don't mind, I'd rather commit my changes.

@DGuidi
Copy link
Contributor

DGuidi commented Nov 6, 2020

Additionally I made the the unit tests pass, there were a lot failing...

do you mean, they fails in android?

If you don't mind, I'd rather commit my changes.

of course, thanks

@DGuidi DGuidi removed the question Further information is requested label Nov 6, 2020
@ssrodnas
Copy link

Hi all,

On Android I have the same issue as the original issue describes.
I tried out the solution recommended by @FObermaier, and it solves the issue
(adding the "Encoding.GetEncoding(codePage);" as fallback)

public static Encoding GetEncodingForCodePageIdentifier(int codePage) => CodePagesEncodingProvider.Instance.GetEncoding(codePage) ?? Encoding.GetEncoding(codePage);

Just wondering if there is any reason why it is not merged to the implementation?
Without this, I'm not able to read the ShapeFile on Android, unless I use the source code of the NetTopologySuite.IO.ShapeFile, and add that fallback manually, but in that case I won't be able to get updates later.

Thanks,
S.

@KubaSzostak
Copy link
Member

Hi @benabdelkrim, do you need more support on this issue? If so, provide further details, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working waiting for feedback
Projects
None yet
Development

No branches or pull requests

5 participants