Trouble calling ltic_getMetadataRecord from c#

For discussion of LizardTech's free Decode SDK for MrSID and JPEG 2000.

Moderator: jskiffington

Trouble calling ltic_getMetadataRecord from c#

Postby bengecko » Fri Oct 02, 2009 9:19 pm

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
bengecko
 
Posts: 4
Joined: Fri Oct 02, 2009 9:12 pm

Postby mpg » Mon Oct 05, 2009 12:58 pm

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
mpg
 
Posts: 29
Joined: Thu Jan 24, 2008 1:50 pm
Location: LizardTech

Postby bengecko » Mon Oct 05, 2009 1:04 pm

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);

}
bengecko
 
Posts: 4
Joined: Fri Oct 02, 2009 9:12 pm

Postby mpg » Tue Oct 06, 2009 8:08 am

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
mpg
 
Posts: 29
Joined: Thu Jan 24, 2008 1:50 pm
Location: LizardTech

Postby bengecko » Tue Oct 06, 2009 9:05 am

That works great. Thanks for the sample.
bengecko
 
Posts: 4
Joined: Fri Oct 02, 2009 9:12 pm


Return to SDKs

Who is online

Users browsing this forum: No registered users and 1 guest

cron