【C#】.NET で GDAL を使うには... ~ Hello World編 ~

■ はじめに

https://blogs.yahoo.co.jp/dk521123/38092205.html
の続き。
今回は、簡単なサンプルを動かす。
なお、公式サイトのサンプルを参考(ほぼコピペ)にした
C#のサンプル
https://trac.osgeo.org/gdal/browser/trunk/gdal/swig/csharp/apps

■ サンプル

 * 入力するGeoTIFFファイルは、以下のサイトのものを使う
https://www.eorc.jaxa.jp/ALOS-2/doc/sam_jindex.htm

GdalConfiguration.cs

NuGetでインストール後、「GdalConfiguration.cs」がダウンロードされるので、それを修正
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Gdal = OSGeo.GDAL.Gdal;
using Ogr = OSGeo.OGR.Ogr;

namespace SampleForm
{
  public static partial class GdalConfiguration
  {
    private static volatile bool _configuredOgr;
    private static volatile bool _configuredGdal;
    private static volatile bool _usable;

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    static extern bool SetDefaultDllDirectories(uint directoryFlags);
    //               LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32
    private const uint DllSearchFlags = 0x00000400 | 0x00000800;

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AddDllDirectory(string lpPathName);

    /// <summary>
    /// Construction of Gdal/Ogr
    /// </summary>
    static GdalConfiguration()
    {
      //      string executingDirectory = null;
      string gdalPath = @"C:\Program Files\GDAL";
      string nativePath = @"C:\Program Files\GDAL";
      try
      {
        if (!IsWindows)
        {
          const string notSet = "_Not_set_";
          string tmp = Gdal.GetConfigOption("GDAL_DATA", notSet);
          _usable = tmp != notSet;
          return;
        }

        //string executingAssemblyFile = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath;
        //executingDirectory = Path.GetDirectoryName(executingAssemblyFile);

        //if (string.IsNullOrEmpty(executingDirectory))
        //  throw new InvalidOperationException("cannot get executing directory");


        // modify search place and order
        SetDefaultDllDirectories(DllSearchFlags);

        //gdalPath = Path.Combine(executingDirectory, "gdal");
        //nativePath = Path.Combine(gdalPath, GetPlatform());
        if (!Directory.Exists(nativePath))
          throw new DirectoryNotFoundException($"GDAL native directory not found at '{nativePath}'");
        if (!File.Exists(Path.Combine(nativePath, "gdal_wrap.dll")))
          throw new FileNotFoundException(
              $"GDAL native wrapper file not found at '{Path.Combine(nativePath, "gdal_wrap.dll")}'");

        // Add directories
        AddDllDirectory(nativePath);
        AddDllDirectory(Path.Combine(nativePath, "gdalplugins"));

        // Set the additional GDAL environment variables.
        string gdalData = Path.Combine(gdalPath, "gdal-data");
        Environment.SetEnvironmentVariable("GDAL_DATA", gdalData);
        Gdal.SetConfigOption("GDAL_DATA", gdalData);

        string driverPath = Path.Combine(nativePath, "gdalplugins");
        Environment.SetEnvironmentVariable("GDAL_DRIVER_PATH", driverPath);
        Gdal.SetConfigOption("GDAL_DRIVER_PATH", driverPath);

        Environment.SetEnvironmentVariable("GEOTIFF_CSV", gdalData);
        Gdal.SetConfigOption("GEOTIFF_CSV", gdalData);

        string projSharePath = Path.Combine(gdalPath, "projlib");
        Environment.SetEnvironmentVariable("PROJ_LIB", projSharePath);
        Gdal.SetConfigOption("PROJ_LIB", projSharePath);

        _usable = true;
      }
      catch (Exception ex)
      {
        _usable = false;
        Trace.WriteLine(ex, "error");
        //Trace.WriteLine($"Executing directory: {executingDirectory}", "error");
        Trace.WriteLine($"gdal directory: {gdalPath}", "error");
        Trace.WriteLine($"native directory: {nativePath}", "error");

        //throw;
      }
    }

    /// <summary>
    /// Gets a value indicating if the GDAL package is set up properly.
    /// </summary>
    public static bool Usable
    {
      get { return _usable; }
    }

    /// <summary>
    /// Method to ensure the static constructor is being called.
    /// </summary>
    /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
    public static void ConfigureOgr()
    {
      if (!_usable) return;
      if (_configuredOgr) return;

      // Register drivers
      Ogr.RegisterAll();
      _configuredOgr = true;

      PrintDriversOgr();
    }

    /// <summary>
    /// Method to ensure the static constructor is being called.
    /// </summary>
    /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks>
    public static void ConfigureGdal()
    {
      if (!_usable) return;
      if (_configuredGdal) return;

      // Register drivers
      Gdal.AllRegister();
      _configuredGdal = true;

      PrintDriversGdal();
    }


    /// <summary>
    /// Function to determine which platform we're on
    /// </summary>
    private static string GetPlatform()
    {
      return Environment.Is64BitProcess ? "x64" : "x86";
    }

    /// <summary>
    /// Gets a value indicating if we are on a windows platform
    /// </summary>
    private static bool IsWindows
    {
      get
      {
        var res = !(Environment.OSVersion.Platform == PlatformID.Unix ||
                    Environment.OSVersion.Platform == PlatformID.MacOSX);

        return res;
      }
    }
    private static void PrintDriversOgr()
    {
#if DEBUG
      if (_usable)
      {
        var num = Ogr.GetDriverCount();
        for (var i = 0; i < num; i++)
        {
          var driver = Ogr.GetDriver(i);
          Trace.WriteLine($"OGR {i}: {driver.GetName()}", "Debug");
        }
      }
#endif
    }

    private static void PrintDriversGdal()
    {
      if (_usable)
      {
        var num = Gdal.GetDriverCount();
        for (var i = 0; i < num; i++)
        {
          var driver = Gdal.GetDriver(i);
          Trace.WriteLine($"GDAL {i}: {driver.ShortName}-{driver.LongName}");
        }
      }
    }
  }
}

Form1.cs

公式サイトの以下のサンプルを参考に実装
https://trac.osgeo.org/gdal/browser/trunk/gdal/swig/csharp/apps/GDALInfo.cs
using OSGeo.GDAL;
using System;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      string file = @"0000008658_001001_ALOS2014410740-140829\IMG-HH-ALOS2014410740-140829-UBSL1.5GUA.tif";
      try
      {
        GdalConfiguration.ConfigureGdal();

        /* -------------------------------------------------------------------- */
        /*      Open dataset.                                                   */
        /* -------------------------------------------------------------------- */
        Dataset ds = Gdal.Open(file, Access.GA_ReadOnly);

        if (ds == null)
        {
          Console.WriteLine("Can't open " + file);
          System.Environment.Exit(-1);
        }

        Console.WriteLine("Raster dataset parameters:");
        Console.WriteLine("  Projection: " + ds.GetProjectionRef());
        Console.WriteLine("  RasterCount: " + ds.RasterCount);
        Console.WriteLine("  RasterSize (" + ds.RasterXSize + "," + ds.RasterYSize + ")");

        /* -------------------------------------------------------------------- */
        /*      Get driver                                                      */
        /* -------------------------------------------------------------------- */
        Driver drv = ds.GetDriver();

        if (drv == null)
        {
          Console.WriteLine("Can't get driver.");
          System.Environment.Exit(-1);
        }

        Console.WriteLine("Using driver " + drv.LongName);

        /* -------------------------------------------------------------------- */
        /*      Get metadata                                                    */
        /* -------------------------------------------------------------------- */
        string[] metadata = ds.GetMetadata("");
        if (metadata.Length > 0)
        {
          Console.WriteLine("  Metadata:");
          for (int iMeta = 0; iMeta < metadata.Length; iMeta++)
          {
            Console.WriteLine("    " + iMeta + ":  " + metadata[iMeta]);
          }
          Console.WriteLine("");
        }

        /* -------------------------------------------------------------------- */
        /*      Report "IMAGE_STRUCTURE" metadata.                              */
        /* -------------------------------------------------------------------- */
        metadata = ds.GetMetadata("IMAGE_STRUCTURE");
        if (metadata.Length > 0)
        {
          Console.WriteLine("  Image Structure Metadata:");
          for (int iMeta = 0; iMeta < metadata.Length; iMeta++)
          {
            Console.WriteLine("    " + iMeta + ":  " + metadata[iMeta]);
          }
          Console.WriteLine("");
        }

        /* -------------------------------------------------------------------- */
        /*      Report subdatasets.                                             */
        /* -------------------------------------------------------------------- */
        metadata = ds.GetMetadata("SUBDATASETS");
        if (metadata.Length > 0)
        {
          Console.WriteLine("  Subdatasets:");
          for (int iMeta = 0; iMeta < metadata.Length; iMeta++)
          {
            Console.WriteLine("    " + iMeta + ":  " + metadata[iMeta]);
          }
          Console.WriteLine("");
        }

        /* -------------------------------------------------------------------- */
        /*      Report geolocation.                                             */
        /* -------------------------------------------------------------------- */
        metadata = ds.GetMetadata("GEOLOCATION");
        if (metadata.Length > 0)
        {
          Console.WriteLine("  Geolocation:");
          for (int iMeta = 0; iMeta < metadata.Length; iMeta++)
          {
            Console.WriteLine("    " + iMeta + ":  " + metadata[iMeta]);
          }
          Console.WriteLine("");
        }

        /* -------------------------------------------------------------------- */
        /*      Report corners.                                                 */
        /* -------------------------------------------------------------------- */
        Console.WriteLine("Corner Coordinates:");
        Console.WriteLine("  Upper Left (" + GDALInfoGetPosition(ds, 0.0, 0.0) + ")");
        Console.WriteLine("  Lower Left (" + GDALInfoGetPosition(ds, 0.0, ds.RasterYSize) + ")");
        Console.WriteLine("  Upper Right (" + GDALInfoGetPosition(ds, ds.RasterXSize, 0.0) + ")");
        Console.WriteLine("  Lower Right (" + GDALInfoGetPosition(ds, ds.RasterXSize, ds.RasterYSize) + ")");
        Console.WriteLine("  Center (" + GDALInfoGetPosition(ds, ds.RasterXSize / 2, ds.RasterYSize / 2) + ")");
        Console.WriteLine("");

        /* -------------------------------------------------------------------- */
        /*      Report GCPs.                                                    */
        /* -------------------------------------------------------------------- */
        if (ds.GetGCPCount() > 0)
        {
          Console.WriteLine("GCP Projection: ", ds.GetGCPProjection());
          GCP[] GCPs = ds.GetGCPs();
          for (int i = 0; i < ds.GetGCPCount(); i++)
          {
            Console.WriteLine("GCP[" + i + "]: Id=" + GCPs[i].Id + ", Info=" + GCPs[i].Info);
            Console.WriteLine("          (" + GCPs[i].GCPPixel + "," + GCPs[i].GCPLine + ") -> ("
                        + GCPs[i].GCPX + "," + GCPs[i].GCPY + "," + GCPs[i].GCPZ + ")");
            Console.WriteLine("");
          }
          Console.WriteLine("");

          double[] transform = new double[6];
          Gdal.GCPsToGeoTransform(GCPs, transform, 0);
          Console.WriteLine("GCP Equivalent geotransformation parameters: ", ds.GetGCPProjection());
          for (int i = 0; i < 6; i++)
            Console.WriteLine("t[" + i + "] = " + transform[i].ToString());
          Console.WriteLine("");
        }

        /* -------------------------------------------------------------------- */
        /*      Get raster band                                                 */
        /* -------------------------------------------------------------------- */
        for (int iBand = 1; iBand <= ds.RasterCount; iBand++)
        {
          Band band = ds.GetRasterBand(iBand);
          Console.WriteLine("Band " + iBand + " :");
          Console.WriteLine("   DataType: " + Gdal.GetDataTypeName(band.DataType));
          Console.WriteLine("   ColorInterpretation: " + Gdal.GetColorInterpretationName(band.GetRasterColorInterpretation()));
          ColorTable ct = band.GetRasterColorTable();
          if (ct != null)
            Console.WriteLine("   Band has a color table with " + ct.GetCount() + " entries.");

          Console.WriteLine("   Description: " + band.GetDescription());
          Console.WriteLine("   Size (" + band.XSize + "," + band.YSize + ")");
          int BlockXSize, BlockYSize;
          band.GetBlockSize(out BlockXSize, out BlockYSize);
          Console.WriteLine("   BlockSize (" + BlockXSize + "," + BlockYSize + ")");
          double val;
          int hasval;
          band.GetMinimum(out val, out hasval);
          if (hasval != 0) Console.WriteLine("   Minimum: " + val.ToString());
          band.GetMaximum(out val, out hasval);
          if (hasval != 0) Console.WriteLine("   Maximum: " + val.ToString());
          band.GetNoDataValue(out val, out hasval);
          if (hasval != 0) Console.WriteLine("   NoDataValue: " + val.ToString());
          band.GetOffset(out val, out hasval);
          if (hasval != 0) Console.WriteLine("   Offset: " + val.ToString());
          band.GetScale(out val, out hasval);
          if (hasval != 0) Console.WriteLine("   Scale: " + val.ToString());

          for (int iOver = 0; iOver < band.GetOverviewCount(); iOver++)
          {
            Band over = band.GetOverview(iOver);
            Console.WriteLine("      OverView " + iOver + " :");
            Console.WriteLine("         DataType: " + over.DataType);
            Console.WriteLine("         Size (" + over.XSize + "," + over.YSize + ")");
            Console.WriteLine("         PaletteInterp: " + over.GetRasterColorInterpretation().ToString());
          }
        }
      }
      catch (Exception ex)
      {
        Console.WriteLine("Application error: " + ex.Message);
      }
    }

    private static string GDALInfoGetPosition(Dataset ds, double x, double y)
    {
      double[] adfGeoTransform = new double[6];
      double dfGeoX, dfGeoY;
      ds.GetGeoTransform(adfGeoTransform);

      dfGeoX = adfGeoTransform[0] + adfGeoTransform[1] * x + adfGeoTransform[2] * y;
      dfGeoY = adfGeoTransform[3] + adfGeoTransform[4] * x + adfGeoTransform[5] * y;

      return dfGeoX.ToString() + ", " + dfGeoY.ToString();
    }
  }
}

出力結果

GDAL 0: BAG-Bathymetry Attributed Grid
・・・途中略・・・
GDAL 216: ISCE-ISCE raster
GDAL 217: HTTP-HTTP Fetching Wrapper
・・・途中略・・・

Corner Coordinates:
  Upper Left (357907.598706947, 3994193.44192625)
  Lower Left (357907.598706947, 3912185.94192625)
  Upper Right (430720.098706947, 3994193.44192625)
  Lower Right (430720.098706947, 3912185.94192625)
  Center (394312.598706947, 3953190.94192625)

Band 1 :
   DataType: UInt16
   ColorInterpretation: Gray
   Description: 
   Size (29125,32803)
   BlockSize (29125,1)
   Offset: 0
   Scale: 1

関連記事

C#

.NET で GDAL を使うには... ~ 環境設定編 ~
https://blogs.yahoo.co.jp/dk521123/38092205.html
.NET で GDAL・gdalwarpを実行するには... [1]
https://blogs.yahoo.co.jp/dk521123/38098235.html
.NET で GDAL・gdalwarpを実行するには... [2]
https://blogs.yahoo.co.jp/dk521123/38100111.html

GISツール

GISツール ~ GDAL / OGR ~
https://blogs.yahoo.co.jp/dk521123/38092840.html
GISツール ~ GDALコマンド ~
https://blogs.yahoo.co.jp/dk521123/38093845.html