wms_gdal_drv.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. """!
  2. @brief GDAL WMS driver.
  3. List of classes:
  4. - wms_drv::NullDevice
  5. - wms_drv::WMSGdalDrv
  6. (C) 2012-2021 by the GRASS Development Team
  7. This program is free software under the GNU General Public License
  8. (>=v2). Read the file COPYING that comes with GRASS for details.
  9. @author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
  10. """
  11. import grass.script as grass
  12. try:
  13. from osgeo import gdal
  14. except:
  15. grass.fatal(
  16. _(
  17. "Unable to load GDAL Python bindings (requires package 'python-gdal' being installed)"
  18. )
  19. )
  20. import xml.etree.ElementTree as etree
  21. from wms_base import WMSBase, GetSRSParamVal
  22. class NullDevice:
  23. def write(self, s):
  24. pass
  25. class WMSGdalDrv(WMSBase):
  26. def __init__(self, createopt):
  27. super(WMSGdalDrv, self).__init__()
  28. self.proxy = None
  29. self.proxy_user_pw = None
  30. self.createopt = createopt
  31. def setProxy(self, proxy, proxy_user_pw=None):
  32. """Set the HTTP proxy and its user and password
  33. @input proxy HTTP proxy with [IP address]:[port]
  34. @input proxy_user_pw with [user name]:[password]
  35. """
  36. self.proxy = proxy
  37. self.proxy_user_pw = proxy_user_pw
  38. def _createXML(self):
  39. """!Create XML for GDAL WMS driver
  40. @return path to XML file
  41. """
  42. self._debug("_createXML", "started")
  43. gdal_wms = etree.Element("GDAL_WMS")
  44. service = etree.SubElement(gdal_wms, "Service")
  45. name = etree.Element("name")
  46. service.set("name", "WMS")
  47. version = etree.SubElement(service, "Version")
  48. version.text = self.params["wms_version"]
  49. server_url = etree.SubElement(service, "ServerUrl")
  50. server_url.text = self.params["url"]
  51. srs = etree.SubElement(service, self.params["proj_name"])
  52. srs.text = GetSRSParamVal(self.params["srs"])
  53. image_format = etree.SubElement(service, "ImageFormat")
  54. image_format.text = self.params["format"]
  55. image_format = etree.SubElement(service, "Transparent")
  56. image_format.text = self.params["transparent"]
  57. layers = etree.SubElement(service, "Layers")
  58. layers.text = self.params["layers"]
  59. styles = etree.SubElement(service, "Styles")
  60. styles.text = self.params["styles"]
  61. data_window = etree.SubElement(gdal_wms, "DataWindow")
  62. upper_left_x = etree.SubElement(data_window, "UpperLeftX")
  63. upper_left_x.text = str(self.bbox["minx"])
  64. upper_left_y = etree.SubElement(data_window, "UpperLeftY")
  65. upper_left_y.text = str(self.bbox["maxy"])
  66. lower_right_x = etree.SubElement(data_window, "LowerRightX")
  67. lower_right_x.text = str(self.bbox["maxx"])
  68. lower_right_y = etree.SubElement(data_window, "LowerRightY")
  69. lower_right_y.text = str(self.bbox["miny"])
  70. size_x = etree.SubElement(data_window, "SizeX")
  71. size_x.text = str(self.region["cols"])
  72. size_y = etree.SubElement(data_window, "SizeY")
  73. size_y.text = str(self.region["rows"])
  74. # RGB + alpha
  75. self.temp_map_bands_num = 4
  76. block_size_x = etree.SubElement(gdal_wms, "BandsCount")
  77. block_size_x.text = str(self.temp_map_bands_num)
  78. block_size_x = etree.SubElement(gdal_wms, "BlockSizeX")
  79. block_size_x.text = str(self.tile_size["cols"])
  80. block_size_y = etree.SubElement(gdal_wms, "BlockSizeY")
  81. block_size_y.text = str(self.tile_size["rows"])
  82. if self.params["username"] and self.params["password"]:
  83. user_password = etree.SubElement(gdal_wms, "UserPwd")
  84. user_password.text = "%s:%s" % (
  85. self.params["username"],
  86. self.params["password"],
  87. )
  88. xml_file = self._tempfile()
  89. etree.ElementTree(gdal_wms).write(xml_file)
  90. self._debug("_createXML", "finished -> %s" % xml_file)
  91. return xml_file
  92. def _download(self):
  93. """!Downloads data from WMS server using GDAL WMS driver
  94. @return temp_map with stored downloaded data
  95. """
  96. grass.message("Downloading data from WMS server...")
  97. # GDAL WMS driver does not flip geographic coordinates
  98. # according to WMS standard 1.3.0.
  99. if (
  100. "+proj=latlong" in self.proj_srs or "+proj=longlat" in self.proj_srs
  101. ) and self.params["wms_version"] == "1.3.0":
  102. grass.warning(
  103. _(
  104. "If module will not be able to fetch the data in this "
  105. + "geographic projection, \n try 'WMS_GRASS' driver or use WMS version 1.1.1."
  106. )
  107. )
  108. self._debug("_download", "started")
  109. temp_map = self._tempfile()
  110. xml_file = self._createXML()
  111. # print xml file content for debug level 1
  112. file = open(xml_file, "r")
  113. grass.debug("WMS request XML:\n%s" % file.read(), 1)
  114. file.close()
  115. if self.proxy:
  116. gdal.SetConfigOption("GDAL_HTTP_PROXY", str(self.proxy))
  117. if self.proxy_user_pw:
  118. gdal.SetConfigOption("GDAL_HTTP_PROXYUSERPWD", str(self.proxy_user_pw))
  119. wms_dataset = gdal.Open(xml_file, gdal.GA_ReadOnly)
  120. grass.try_remove(xml_file)
  121. if wms_dataset is None:
  122. grass.fatal(_("Unable to open GDAL WMS driver"))
  123. self._debug("_download", "GDAL dataset created")
  124. driver = gdal.GetDriverByName(self.gdal_drv_format)
  125. if driver is None:
  126. grass.fatal(_("Unable to find %s driver" % format))
  127. metadata = driver.GetMetadata()
  128. if (
  129. gdal.DCAP_CREATECOPY not in metadata
  130. or metadata[gdal.DCAP_CREATECOPY] == "NO"
  131. ):
  132. grass.fatal(
  133. _("Driver %s supports CreateCopy() method.") % self.gdal_drv_name
  134. )
  135. self._debug("_download", "calling GDAL CreateCopy...")
  136. if self.createopt is None:
  137. temp_map_dataset = driver.CreateCopy(temp_map, wms_dataset, 0)
  138. else:
  139. self._debug("_download", "Using GDAL createopt <%s>" % str(self.createopt))
  140. temp_map_dataset = driver.CreateCopy(
  141. temp_map, wms_dataset, 0, self.createopt
  142. )
  143. if temp_map_dataset is None:
  144. grass.fatal(_("Incorrect WMS query"))
  145. temp_map_dataset = None
  146. wms_dataset = None
  147. self._debug("_download", "finished")
  148. return temp_map