Proper use of ConstructMarkerFromBitmapSource

390
1
06-29-2019 07:42 PM
MatthewJackson3
New Contributor II

Good Evening,

I am trying to use ConstructMarkerFromBitmapSource in v2.3 of the SDK with a CIMUniqueValueRenderer to generate symbology for a series of point features. When I do so, I am getting rather cryptic COM exceptions.  Below is a snippet that results in a COM exception when applying to a feature class. Any ideas?

Thanks,

Matt

var r = new CIMUniqueValueRenderer
{
    Fields = new string[] { "type" }
};
//r.Groups = new CIMUniqueValueGroup[] { IncidentGroup() };
var uri = new Uri("pack://application:,,,/SamplePlugin;component/Images/blue_circle-16.png");
var img = new BitmapImage(uri);
var marker = SymbolFactory.Instance.ConstructMarkerFromBitmapSource(img) ;
var symbol = SymbolFactory.Instance.ConstructPointSymbol(marker);
r.UseDefaultSymbol = true;
r.DefaultSymbol = symbol.MakeSymbolReference();
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
1 Reply
MatthewJackson3
New Contributor II

Did some more investigation this morning. It appears to be due to ConstructMarkerFromBitmapSource assuming the underlying encoding is a bitmap. Unfortunately for me, I was using png's/gif's, and I'm guessing somewhere in the C/C++ backend, the code is trying to parse my png or gif as a bmp. Interestingly enough, the ConstructMarkerFromFile function seems to work fine, so somewhere in there it must be properly testing the extension or parsing the codec before converting it to the URL format that is expected by CIMPictureMarker...

At any rate, I circumvented the issue by using CIMPictureMarker, and then forming the correct URL string expected by testing the codec type. Hopefully the snippet below will save someone else some time...

private static CIMPictureMarker GetMarker(string type)
{
    Uri uri;
    if (type == "Type I")
        uri = new Uri("pack://application:,,,/ExamplePlugin;component/Images/type1.gif");
    else if (type == "Type II")
        uri = new Uri("pack://application:,,,/ExamplePlugin;component/Images/type2.png");
    else if (type == "Type III")
        uri = new Uri("pack://application:,,,/ExamplePlugin;component/Images/type3.jpg");
    else
        uri = new Uri("pack://application:,,,/ExamplePlugin;component/Images/unknown.png");
    
    var marker = new CIMPictureMarker()
    {
        Size = 16, // for this use case, I want to use 16. Otherwise the icons look too large in the legend...
        URL = BuildPictureMarkerURL(uri)
    };
    return marker;
}
private static string BuildPictureMarkerURL(Uri uri)
{
    var decoder = BitmapDecoder.Create(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    var builder = new StringBuilder();
    builder.Append("data:");
    if (decoder.CodecInfo.MimeTypes.ToLower().Contains("jpeg"))
        builder.Append(decoder.CodecInfo.MimeTypes.Split(',')[0]);
    else
        builder.Append(decoder.CodecInfo.MimeTypes);
    builder.Append(";base64,");
    builder.Append(decoder.ToBase64());
    return builder.ToString();
}
private static string ToBase64(this BitmapDecoder decoder)
{
    var encoder = BitmapEncoder.Create(decoder.CodecInfo.ContainerFormat);
    foreach (var frame in decoder.Frames)
        encoder.Frames.Add(frame);
    using (var stream = new System.IO.MemoryStream())
    {
        encoder.Save(stream);
        return Convert.ToBase64String(stream.ToArray(), Base64FormattingOptions.InsertLineBreaks);
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos