ThinkGeo.com    |     Documentation    |     Premium Support

NativeImageRasterLayer problems in 32-bit application

Hi,

We need to project large raster maps over the background map. These maps can be e.g. 12000*12000 pixels sometimes. This has been working fine on 64-bit application builds, but we have also requirement to support 32-bit operating systems. We’ve noticed problems in 32-bit application builds with these raster files.

I’m using this code to project a PNG file:

    private void mapView_Loaded(object sender, RoutedEventArgs e)
    {
        // Set the Map Unit.
        mapView.MapUnit = GeographyUnit.Meter;

        // Add a base map overlay.
        var cloudRasterBaseMapOverlay = new ThinkGeoCloudRasterMapsOverlay("USlbIyO5uIMja2y0qoM21RRM6NBXUad4hjK3NBD6pD0~", "f6OJsvCDDzmccnevX55nL7nXpPDXXKANe5cN6czVjCH0s8jhpCH-2A~~", ThinkGeoCloudRasterMapsMapType.Light);
        mapView.Overlays.Add(cloudRasterBaseMapOverlay);

        // Add a raster layer
        var layer = new NativeImageRasterLayer(@"AppData/test.png", @"AppData/test.wld");
        layer.ImageSource.ProjectionConverter = new UnmanagedProjectionConverter(3067, 3857);

        layer.Open();
        mapView.CurrentExtent = layer.GetBoundingBox();

        LayerOverlay layerOverlay = new LayerOverlay();
        layerOverlay.Layers.Add(layer);
        mapView.Overlays.Add(layerOverlay);
        mapView.Refresh();
    }

I’m using just a test picture, with no real map data in it just for testing purposes. It looks like this in 64-bit build:


This is basically correct, but that white stripe surrounded with red ellipse should not be there. (I’ve seen this kind of artifacts earlier with projected raster files…)

But if I build a 32-bit app variant, at first it looks the same, but when I zoom in, I get this:

“Unable to allocate pixels for the bitmap.” exception gets printed to the map. Also in our production application we are seeing that the raster file can’t be added to the map at all. Layer.Open throws this exception:

MapCoreTestClient.exe Error: 0 : MapCore.Model.LayerImportResult|Exception|System.Exception: Unable to allocate pixels for the bitmap.
   at SkiaSharp.SKBitmap..ctor(SKImageInfo info, Int32 rowBytes)
   at SkiaSharp.SKBitmap.Decode(SKCodec codec, SKImageInfo bitmapInfo)
   at SkiaSharp.SKBitmap.Decode(SKCodec codec)
   at SkiaSharp.SKBitmap.Decode(String filename)
   at ThinkGeo.Core.NativeImageRasterSource.OpenCore()
   at ThinkGeo.Core.RasterSource.Open()
   at ThinkGeo.Core.RasterLayer.OpenCore()
   at ThinkGeo.Core.Layer.Open()

Is there something that can be done to make this work?

I have added the test project here as reference. It has both AnyCPU and x86 build configurations.ThinkGeo32Bit.zip (38.5 KB)

Thanks,
Rasmus

Hi Rasmus,

Thanks for your detailed sample, we have recreated this problem which is proved to be a memory issue, we are working on it now and will see if any options that we can work around it, any progress I will keep you posted.

Thanks,
Johnny

Hi Rasmus,

This issue is fixed in the latest beta version (ThinkGeo.Core Beta275 and later). Please have a try.

X86 does have strict memory limits and we still recommend you to use X64 especially when launching a big raster file.

Let us know if you have more issues.

Thanks,
Ben

Also Rasmus,

Please use singletile for the overlay. It behaves better for your scenario.

layerOverlay.TileType = TileType.SingleTile;

Thanks,
Ben

Hi Ben,

It works probably a bit better, but if I just zoom in and out a couple of times with mouse wheel or change the window size, I get the application to crash very easily. I don’t get a stack trace, only this line:

The program ‘[20144] ThinkGeo32Bit.exe’ has exited with code -1073740791 (0xc0000409).

I tried also with TileType.SingleTile and the same crash occurred. I’m not sure, but it might have stayed up for a little while longer and more effort was needed to get the application to crash.

Thanks,
Rasmus

Hi Ben,

Also another finding is that on this provided test app, the raster file loading seems to succeed, but on our production application I’m still getting the same exception, but not always… The application itself takes more memory and resources than the simple test application provided here, so would that be an explanation?

I also tried to reduce the raster file size to one quarter, and that seems to work a bit better, but I was still able to get crash whilst zooming or resizing window.

Do you think that this problem is still somehow solvable or do we need to implement workaround, e.g. restrict the raster file resolution, etc.?

Thanks, Rasmus

Rasmus,

Thanks for the further information, it’s an issue in Skia which is used for drawing in SDK. A bit complicated to get it resolved, but now we are trying some options to work it around. May need some time. Sorry for the delay.

Thanks,
Johnny

Hi Johnny,

No problem, thanks for looking into this.

BR, Rasmus

Hi,

Has there been any progress on this issue?

BR, Rasmus

We have a work around that should solve your issues however it’s not a comprehensive fix. We converted your file to a Jpeg2000 image and added a NuGet package ThinkGeo.Jpeg2000. We then modified one line to use the Jpeg2000 instead of the png and it’s working fine, no crashes in single tile. I didn’t test with multi tile as I think single tile looks better for a re-projected image like this. We also used a free jpeg2000 converter found on the web.

Test Image
test.zip (60.7 KB)

 Jpeg2000RasterLayer layer = new Jpeg2000RasterLayer(@"AppData/test.jp2", @"AppData/test.wld");

Hi David,

Jpeg2000 could be a workaround in some cases, but not always. Our customers are using the application to import their own files and we want to support many different file formats (PNG, GIF, Jpeg, TIFF, GeoTIFF, GeoPDF), so allowing only Jpeg2000 would be too restrictive. Conversion could be somewhat tricky e.g. with GeoTIFF and GeoPDF, which have coordinate system and projection information embedded in the file…

If this unhandled exception occurs in SkiaSharp, is there a possibility to report the problem to SkiaSharp development group to see if they can fix it? I can’t trace the problem deep enough as ThinkGeo is calling the SkiaSharp APIs, so I have no clue which methods are causing this exception.

BR, Rasmus

Hello,

Any chance of pushing SkiaSharp to fix this issue, or work around the problem somehow inside the ThinkGeo engine?

BR, Rasmus

Hey @Rasmus_Rahunen,

Unfortunately, it seems that a workaround for this problem is a bit complicated. I’m seeing multiple issues in Skia’s issue tracker that are tangentially related to the size limitations for x86 applications that have been open for 3+ years. I imagine that fixes for x86 is a low priority for them.

As for a workaround within our software, that will prove quite difficult to achieve outside of the modifications that Ben made awhile ago for you. Perhaps a more simple solution would be to have users running on x86 machines to use cut up versions of these large images as opposed to the single large image. Where ever these images are being generated from could probably have some process that cuts them into 2x2 chunks and the users could add 4 images to the map instead.

Thanks,
Kyle

Hi Kyle,

Ok, thank you for the explanation. We’ll try to manage.

BR, Rasmus

Hey @Rasmus_Rahunen,

You’re welcome. Sorry there is not a comprehensive fix for this.

Thanks,
Kyle

Hi @Rasmus_Rahunen,

If you still have this issue, can you try GdalRasterLayer instead? Install ThinkGeo.Gdal from nuget and you can use it.

        // test.jpg is over 3000px * 5000px
        // It throws “Unable to allocate pixels for the bitmap.” exception.
        // NativeImageRasterLayer layer = new NativeImageRasterLayer(@"d:\test.jpg");

        // GdalRasterLayer works fine loading the same image file. 
        GdalRasterLayer layer = new GdalRasterLayer(@"d:\test.jpg");
        layer.Open();
        GeoImage image = new GeoImage(800, 800);
        GeoCanvas canvas = new SkiaGeoCanvas();
        canvas.BeginDrawing(image, layer.GetBoundingBox(), GeographyUnit.Meter);
        layer.Draw(canvas, new System.Collections.ObjectModel.Collection<SimpleCandidate>());
        canvas.EndDrawing();
        image.Save("d:\\test\\2.png");

Thanks,
Ben