Page 1 of 1
Trouble calling ltic_getMetadataRecord from c#

Posted:
Fri Oct 02, 2009 9:19 pm
by bengecko
I am trying to load into a c# program the meta data, and I can't figure out the numDims, Dims, and data parameters.
I get the tag and datatype back.
Does anyone have an example?
Thanks

Posted:
Mon Oct 05, 2009 12:58 pm
by mpg
How are you accessing the C++ libraries -- via interop, or..?
If you can post the code you have so far, I'd be happy to take a look.
-mpg

Posted:
Mon Oct 05, 2009 1:04 pm
by bengecko
So here is the signature that I have for the Interop call
[DllImport("lti_dsdk_cdll.dll")]
private static extern int ltic_getMetadataRecord(IntPtr image,
UInt32 recordNum,
out string tag,
out int dataType,
ref uint numDims,
out uint[] dims,
ref IntPtr data);
I get values back for the tag, dataType, numDims, but am not sure how to get the dims, and data values back. And quite likely I have the above signature wrong.
The code is below. It is based on the samples posted on the LizardTech blog.
-------------------------------------------------
sts = ltic_openMrSIDImageFile(out image, infile);
Check(sts);
// get some basic properties of the image
uint height = ltic_getHeight(image);
uint width = ltic_getWidth(image);
ushort numBands = ltic_getNumBands(image);
double x = ltic_getGeoXOrigin(image);
double y = ltic_getGeoYOrigin(image);
double xRes = ltic_getGeoXResolution(image);
double yRes = ltic_getGeoYResolution(image);
double xRot = ltic_getGeoXRotation(image);
double yRot = ltic_getGeoYRotation(image);
double minMag = ltic_getMinMagnification(image);
double maxMag = ltic_getMaxMagnification(image);
int numRows = Convert.ToInt32(ltic_getNumMetadataRecords(image));
for (int i = 0; i < numRows; i++)
{
string tag;
int datatype;
uint numDims = 0;
IntPtr zero = IntPtr.Zero;
uint[] dims;
sts = ltic_getMetadataRecord(image, Convert.ToUInt32(i), out tag, out datatype,
ref numDims, out dims, ref zero);
Check(sts);
}

Posted:
Tue Oct 06, 2009 8:08 am
by mpg
Accessing the actual data within a metadata record can be an exercise in pointer semantics, I admit -- this is one of the SDK APIs that, in retrospect, I should have done more cleanly. Anyway, try the following...
Your DllImport should be this:
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
[DllImport("lti_dsdk_cdll.dll")]
private static extern uint ltic_getNumMetadataRecords(IntPtr image);
[DllImport("lti_dsdk_cdll.dll")]
private static extern int ltic_getMetadataRecord(IntPtr image,
UInt32 recordNum,
out IntPtr tag,
out int dataType,
out uint numDims,
ref IntPtr dims,
out IntPtr data);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Then add these three helper functions:
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
unsafe private static string ConvertToString(IntPtr p)
{
string s = "";
byte* b = (byte*)p;
while (*b != 0)
{
s += (char)*b;
++b;
}
return s;
}
unsafe private static string ConvertToStringIndirectly(IntPtr p)
{
string s = "";
byte** pb = (byte**)p;
byte* b = *pb;
while (*b != 0)
{
s += (char)*b;
++b;
}
return s;
}
unsafe private static double ConvertToDoubleIndirectly(IntPtr p)
{
double* pd = (double*)p;
double d = *pd;
return d;
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You should then be able to put this block of code inside Main():
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// dump some metadata
uint numRows = ltic_getNumMetadataRecords(image);
for (uint i = 0; i < numRows; i++)
{
IntPtr tagPointer;
int datatype;
uint numDims = 0;
IntPtr dims = IntPtr.Zero;
IntPtr data = IntPtr.Zero;
sts = ltic_getMetadataRecord(image, i, out tagPointer, out datatype, out numDims, ref dims, out data);
string tag = ConvertToString(tagPointer);
Console.WriteLine("metadata item {0}: tag={1}, datatype={2}, numDims={3}", i, tag, datatype, numDims);
if (datatype == 10) // LTI_METADATA_DATATYPE_FLOAT64
{
double d = ConvertToDoubleIndirectly(data);
Console.WriteLine(" double data: {0}", d);
}
else if (datatype == 11) // LTI_METADATA_DATATYPE_ASCII
{
string s = ConvertToStringIndirectly(data);
Console.WriteLine(" ascii data: {0}", s);
}
else
{
throw new NotImplementedException();
}
Check(sts);
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can probably do this more cleanly by using the interop marshaling facilities to get around all the IntPtrs, but this should give you the idea.
Let me know how this goes for you and I'll add this example to the SDK in our next release.
-mpg

Posted:
Tue Oct 06, 2009 9:05 am
by bengecko
That works great. Thanks for the sample.