AGSRaster PNG support

1125
6
02-15-2017 03:11 PM
WorthSparks
New Contributor III

I am unable to load a spatially enabled raster .png file into my map. The raster is made up of three files:

  1. sketch.png
  2. sketch.pgwx
  3. sketch.png.aux.xml

It loads fine in ArcMap. In attachment "ArcMap.png", the red lines are coming from the raster.

By using raster.load(completion: ) to set my own completion block, I was able to see that it is getting an error:

Failed to open raster dataset: /Users/Worth/Library/Developer/CoreSimulator/Devices/5690DA36-3E43-4DE1-881A-CF85BE5E2C43/data/Containers/Bundle/Application/79766C92-DBAD-4169-86AC-1CAECD4FABC9/testMapView.app/sketch.png

Here is my ViewController.swift source code:

import UIKit
import ArcGIS

class ViewController: UIViewController {

    @IBOutlet weak var mapView: AGSMapView!
    private var map: AGSMap!
    private var raster: AGSRaster!
    private var rasterLayer: AGSRasterLayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        // create map with assigned spatial reference "web mercator (alternate sphere)"
        self.map = AGSMap(spatialReference: AGSSpatialReference.webMercator())

        // assign a basemap to map
        self.map.basemap = AGSBasemap.topographic()

        // create raster
        self.raster = AGSRaster(name: "sketch", extension: "png")

        // for debugging, verify we can load the raster
        self.raster.load(completion: { (error: Error?) -> Void in
            if let error = error {
                print(error.localizedDescription)
            }
        })

        // create raster layer using the raster and name it
        self.rasterLayer = AGSRasterLayer(raster: self.raster)
        self.rasterLayer.name = "sketch raster"

        // add rasterLayer to the map's operationalLayers
        self.map.operationalLayers.add(self.rasterLayer)
        for case let layer as AGSLayer in self.map.operationalLayers {
            print("\nSpatial reference for raster layer \"\(layer.name)\":")
            if let spatialReference = layer.spatialReference {
                print("   WKID = \(spatialReference.wkid)\n")
            } else {
                print("   <undefined>\n")
            }
        }

        // assign map to mapView
        self.mapView.map = map

        // zoom to hard-coded Esri Charlotte office location where raster should appear
        let point = AGSPoint(x: -8992543.0, y: 4177500.0, spatialReference: AGSSpatialReference.webMercator())
        let viewpoint = AGSViewpoint(center: point, scale: 2400.0)
        mapView.setViewpoint(viewpoint)

        // use KVO on drawStatus to know when it thinks it is finished drawing
        mapView.addObserver(self, forKeyPath: "drawStatus", options: .new, context: nil)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func observeValue(forKeyPath keyPath: String?,
                               of object:          Any?,
                               change:             [NSKeyValueChangeKey : Any]?,
                               context:            UnsafeMutableRawPointer?) {
        guard let keyPath = keyPath else { return }
        if keyPath == "drawStatus" {
            if mapView.drawStatus == AGSDrawStatus.completed {
                guard let viewpoint = self.mapView.currentViewpoint(with: AGSViewpointType.centerAndScale) else { return }
                print("\ndrawStatus == .completed")
                guard let point = viewpoint.targetGeometry as? AGSPoint else { return }
                print("point: (x: \(point.x), y: \(point.y)), scale: \(viewpoint.targetScale)")
            }
        }
    }
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

What is the best way to load a .png file as a raster in ArcGIS Runtime SDK for iOS?

Tags (2)
0 Kudos
6 Replies
RyanOlson1
Esri Contributor

XCode compresses PNG files and makes them un-readable by our png library. In your target build settings - try setting "Compress PNG Files" to "NO". Then run your project again and it should work.

0 Kudos
WorthSparks
New Contributor III

I had no idea Xcode did that. Thanks. That fixed the loading error. However, the raster still does not appear in the map. Starting on line 36, my code reports the spatial reference for each layer. The raster is the only layer in this test case, and it reports as "<undefined>". Is there perhaps a problem with the world file (.pgwx) or auxiliary file (.aux.xml)?

Do you know if there is an example anywhere that shows a raster being loaded as a layer that has to match the spatial reference already established in the map?

0 Kudos
GagandeepSingh
Occasional Contributor II

Thats because the raster layer is not loaded yet, when you check for the spatial reference. Either wait for the map to load or load the raster layer manually and print the spatial reference.

Also, to avoid compression of png files by Xcode, you can change the `Type` in the `File Inspector` to `Data` or something else.

0 Kudos
WorthSparks
New Contributor III

I moved the spatial reference checking into the completion block and it worked. Thanks! So now I know it is reading the auxiliary file.

It still is not placing the raster in the correct location. I found it placed where the top-left of the raster is at (0,0) in coordinate space (off the coast of Africa). So even though it is reading the auxiliary file (.aux.xml), it doesn't seem to be honoring the target ground control points (<TargetGCPs> in the .aux.xml file).

Also, it is not honoring the alpha band in the .PNG file. I've been trying to find something in the documentation about enabling the alpha band, like with AGSRGBRenderer but have had no luck yet.

0 Kudos
YueWu1
by Esri Regular Contributor
Esri Regular Contributor
0 Kudos
WorthSparks
New Contributor III

Yes. The sample you mention was one of my starting points. However, it only establishes the mapView's spatial reference from the raster itself, which doesn't show it being placed in the world based on its world file. I was able to get my PNG to appear at (0,0). I never was able to get it to appear where the world file and .aux.xml file placed it in ArcMap.

I hate to say it, but I gave up trying. It was becoming more and more evident that a raster was the wrong tool for what I was trying to do. So I switched to using a superimposed UIView with a subview for each PNG. That gave me the ability to apply transformation to each PNG based on current mapView viewpoint. The result keeps each PNG spatially accurate on the map, which, for what I need, looks and performs a lot better anyway.

0 Kudos