[Git][debian-gis-team/pycoast][upstream] New upstream version 1.3.0+dfsg

Antonio Valentino gitlab at salsa.debian.org
Tue Oct 29 06:49:04 GMT 2019



Antonio Valentino pushed to branch upstream at Debian GIS Project / pycoast


Commits:
f59edc8c by Antonio Valentino at 2019-10-29T06:22:50Z
New upstream version 1.3.0+dfsg
- - - - -


23 changed files:

- .travis.yml
- CHANGELOG.md
- docs/source/config.rst
- pycoast/__init__.py
- pycoast/cw_agg.py
- pycoast/cw_base.py
- + pycoast/tests/coasts_and_grid.ini
- + pycoast/tests/coasts_and_grid_agg.ini
- + pycoast/tests/contours_europe_alpha.png
- pycoast/tests/dateline_boundary_cross.png
- pycoast/tests/dateline_cross.png
- pycoast/tests/grid_europe.png
- pycoast/tests/grid_europe_agg.png
- pycoast/tests/grid_europe_agg_txt.png
- pycoast/tests/grid_geos.png
- pycoast/tests/grid_geos_agg.png
- + pycoast/tests/grid_germ.png
- pycoast/tests/grid_nh.png
- pycoast/tests/grid_nh_agg.png
- + pycoast/tests/test_data/test_config.ini
- pycoast/tests/test_pycoast.py
- pycoast/version.py
- setup.py


Changes:

=====================================
.travis.yml
=====================================
@@ -3,9 +3,8 @@ env:
   global:
   # Set defaults to avoid repeating in most cases
   - PYTHON_VERSION=$TRAVIS_PYTHON_VERSION
-  - NUMPY_VERSION=stable
   - MAIN_CMD='python setup.py'
-  - CONDA_DEPENDENCIES='sphinx pillow pyproj coveralls coverage mock aggdraw six pyshp'
+  - CONDA_DEPENDENCIES='sphinx pillow pyproj coveralls coverage mock aggdraw six pyshp pyresample'
   - PIP_DEPENDENCIES=''
   - SETUP_XVFB=False
   - EVENT_TYPE='push pull_request'
@@ -14,9 +13,13 @@ env:
   - CONDA_CHANNEL_PRIORITY='True'
 matrix:
   include:
-  - env: PYTHON_VERSION=2.7
+  - env:
+    - PYTHON_VERSION=2.7
+    - NUMPY_VERSION=1.16
     os: linux
-  - env: PYTHON_VERSION=2.7
+  - env:
+    - PYTHON_VERSION=2.7
+    - NUMPY_VERSION=1.16
     os: osx
   - env: PYTHON_VERSION=3.6
     os: linux
@@ -25,9 +28,16 @@ matrix:
   - env: PYTHON_VERSION=3.6
     os: windows
     language: bash
+  - env: PYTHON_VERSION=3.7
+    os: linux
+  - env: PYTHON_VERSION=3.7
+    os: osx
+  - env: PYTHON_VERSION=3.7
+    os: windows
+    language: bash
 install:
-- git clone --depth 1 git://github.com/astropy/ci-helpers.git
-- source ci-helpers/travis/setup_conda.sh
+  - git clone --depth 1 git://github.com/astropy/ci-helpers.git
+  - source ci-helpers/travis/setup_conda.sh
 script: coverage run --source=pycoast setup.py test
 after_success:
 - if [[ $PYTHON_VERSION == 3.6 ]]; then coveralls; fi


=====================================
CHANGELOG.md
=====================================
@@ -1,3 +1,27 @@
+## Version 1.3.0 (2019/10/25)
+
+### Issues Closed
+
+* [Issue 29](https://github.com/pytroll/pycoast/issues/29) - pycoast compatability issue with pyproj 2+
+* [Issue 26](https://github.com/pytroll/pycoast/issues/26) - inconsitency adding lat labelling on the right (on graticules)... ([PR 33](https://github.com/pytroll/pycoast/pull/33))
+
+In this release 2 issues were closed.
+
+### Pull Requests Merged
+
+#### Bugs fixed
+
+* [PR 33](https://github.com/pytroll/pycoast/pull/33) - Fix #26 ([26](https://github.com/pytroll/pycoast/issues/26))
+
+#### Features added
+
+* [PR 32](https://github.com/pytroll/pycoast/pull/32) - Add dict configuration
+* [PR 30](https://github.com/pytroll/pycoast/pull/30) - Convert to RGBA mode when opening the image for adding coastlines or rivers to file.
+* [PR 25](https://github.com/pytroll/pycoast/pull/25) - Add coordinate grid overlaying from configuration file
+
+In this release 4 pull requests were closed.
+
+
 ## Version 1.2.3 (2019/06/06)
 
 ### Issues Closed
@@ -442,5 +466,3 @@ In this release 3 pull requests were closed.
 - First version. [Esben S. Nielsen]
 
 - First version. [Esben S. Nielsen]
-
-


=====================================
docs/source/config.rst
=====================================
@@ -1,7 +1,7 @@
 Pycoast from a configuration file
 ---------------------------------
 
-If you want to run to avoid typing the same options over and over again, of if
+If you want to run to avoid typing the same options over and over again, or if
 caching is an optimization you want, you can use a configuration file with the
 pycoast options you need:
 
@@ -9,13 +9,14 @@ pycoast options you need:
 
   [cache]
   file=/var/run/satellit/white_overlay
-  
+  regenerate=False
+
   [coasts]
   level=1
   width=0.75
   outline=white
   fill=yellow
-  
+
   [borders]
   outline=white
   width=0.5


=====================================
pycoast/__init__.py
=====================================
@@ -1,12 +1,12 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
-from .version import get_versions
-__version__ = get_versions()['version']
-del get_versions
 
 from .cw_pil import ContourWriterPIL
 from .cw_agg import ContourWriterAGG
-
+from pycoast.cw_base import get_resolution_from_area
+from .version import get_versions
+__version__ = get_versions()['version']
+del get_versions
 
 class ContourWriter(ContourWriterPIL):
     """Writer wrapper for deprecation warning.
@@ -21,4 +21,4 @@ class ContourWriter(ContourWriterPIL):
         import warnings
         warnings.warn("'ContourWriter' has been deprecated please use "
                       "'ContourWriterPIL' or 'ContourWriterAGG' instead", DeprecationWarning)
-        super(ContourWriter, self).__init__(*args, **kwargs)
\ No newline at end of file
+        super(ContourWriter, self).__init__(*args, **kwargs)


=====================================
pycoast/cw_agg.py
=====================================
@@ -326,7 +326,7 @@ class ContourWriterAGG(ContourWriterBase):
                          minor_outline='white', minor_width=0.5,
                          minor_outline_opacity=255, minor_is_tick=True,
                          lon_placement='tb', lat_placement='lr'):
-        """Add a lon-lat grid to an image.
+        """Add a lon-lat grid to an image. The resulting image is in 'RGBA' mode.
 
         :Parameters:
             image : object
@@ -361,6 +361,7 @@ class ContourWriterAGG(ContourWriterBase):
         """
 
         image = Image.open(filename)
+        image = image.convert('RGBA')
         self.add_grid(image, area_def, Dlonlat, dlonlat,
                       font=font, write_text=write_text,
                       fill=fill, fill_opacity=fill_opacity,
@@ -417,7 +418,7 @@ class ContourWriterAGG(ContourWriterBase):
                                level=1, fill=None, fill_opacity=255,
                                outline='white', width=1, outline_opacity=255,
                                x_offset=0, y_offset=0):
-        """Add coastlines to an image file.
+        """Add coastlines to an image file. The resulting image is in 'RGBA' mode.
 
         :Parameters:
             filename : str
@@ -448,6 +449,7 @@ class ContourWriterAGG(ContourWriterBase):
         """
 
         image = Image.open(filename)
+        image = image.convert('RGBA')
         self.add_coastlines(image, area_def, resolution=resolution,
                             level=level, fill=fill,
                             fill_opacity=fill_opacity, outline=outline,
@@ -492,7 +494,7 @@ class ContourWriterAGG(ContourWriterBase):
     def add_borders_to_file(self, filename, area_def, resolution='c',
                             level=1, outline='white', width=1,
                             outline_opacity=255, x_offset=0, y_offset=0):
-        """Add borders to an image file.
+        """Add borders to an image file. The resulting image is in 'RGBA' mode.
 
         :Parameters:
             image : object
@@ -518,6 +520,7 @@ class ContourWriterAGG(ContourWriterBase):
 
         """
         image = Image.open(filename)
+        image = image.convert("RGBA") 
         self.add_borders(image, area_def, resolution=resolution, level=level,
                          outline=outline, width=width,
                          outline_opacity=outline_opacity, x_offset=x_offset,
@@ -562,7 +565,7 @@ class ContourWriterAGG(ContourWriterBase):
     def add_rivers_to_file(self, filename, area_def, resolution='c', level=1,
                            outline='white', width=1, outline_opacity=255,
                            x_offset=0, y_offset=0):
-        """Add rivers to an image file.
+        """Add rivers to an image file. The resulting image is in 'RGBA' mode.
 
         :Parameters:
             image : object
@@ -589,6 +592,7 @@ class ContourWriterAGG(ContourWriterBase):
         """
 
         image = Image.open(filename)
+        image = image.convert("RGBA") 
         self.add_rivers(image, area_def, resolution=resolution, level=level,
                         outline=outline, width=width,
                         outline_opacity=outline_opacity, x_offset=x_offset,


=====================================
pycoast/cw_base.py
=====================================
@@ -20,9 +20,10 @@
 import os
 import shapefile
 import numpy as np
-from PIL import Image, ImageFont
+from PIL import Image
 import pyproj
 import logging
+import ast
 
 try:
     import configparser
@@ -32,6 +33,37 @@ except ImportError:
 logger = logging.getLogger(__name__)
 
 
+def get_resolution_from_area(area_def):
+    """Get the best resolution for an area definition."""
+    x_size = area_def.width
+    y_size = area_def.height
+    prj = Proj(area_def.proj_str)
+    if prj.is_latlong():
+        x_ll, y_ll = prj(area_def.area_extent[0], area_def.area_extent[1])
+        x_ur, y_ur = prj(area_def.area_extent[2], area_def.area_extent[3])
+        x_resolution = (x_ur - x_ll) / x_size
+        y_resolution = (y_ur - y_ll) / y_size
+    else:
+        x_resolution = ((area_def.area_extent[2] -
+                         area_def.area_extent[0]) /
+                        x_size)
+        y_resolution = ((area_def.area_extent[3] -
+                         area_def.area_extent[1]) /
+                        y_size)
+    res = min(x_resolution, y_resolution)
+
+    if res > 25000:
+        return "c"
+    elif res > 5000:
+        return "l"
+    elif res > 1000:
+        return "i"
+    elif res > 200:
+        return "h"
+    else:
+        return "f"
+
+
 class Proj(pyproj.Proj):
     """Wrapper around pyproj to add in 'is_latlong'."""
 
@@ -99,7 +131,7 @@ class ContourWriterBase(object):
 
     def _find_line_intercepts(self, xys, size, margins):
         """Finds intercepts of poly-line xys with image boundaries
-        offset by margins and returns an array of coordintes"""
+        offset by margins and returns an array of coordinates"""
         x_size, y_size = size
 
         def is_in_box(x_y, extents):
@@ -120,13 +152,13 @@ class ContourWriterBase(object):
         xlim1 = margins[0]
         ylim1 = margins[1]
         xlim2 = x_size - margins[0]
-        ylim2 = y_size - margins[0]
+        ylim2 = y_size - margins[1]
 
         # only consider crossing within a box a little bigger than grid
         # boundary
         search_box = (-10, x_size + 10, -10, y_size + 10)
 
-        # loop trought line steps and detect crossings
+        # loop through line steps and detect crossings
         intercepts = []
         align_left = 'LC'
         align_right = 'RC'
@@ -168,7 +200,7 @@ class ContourWriterBase(object):
         """
 
         try:
-            proj4_string = area_def.proj4_string
+            proj4_string = area_def.proj_str
             area_extent = area_def.area_extent
         except AttributeError:
             proj4_string = area_def[0]
@@ -234,7 +266,7 @@ class ContourWriterBase(object):
                              lat_max - shorten_max_lat,
                              float(lat_max - lat_min) / y_size)
         # lin_lats in rather high definition so that it can be used to
-        # posituion text labels near edges of image...
+        # position text labels near edges of image...
 
         # perhaps better to find the actual length of line in pixels...
 
@@ -253,7 +285,7 @@ class ContourWriterBase(object):
 
         # lons along major lat lines (extended slightly to avoid missing the
         # end)
-        lin_lons = np.arange(lon_min, lon_max + Dlon / 5.0, Dlon / 10.0)
+        lin_lons = np.linspace(lon_min, lon_max + Dlon / 5.0, max(x_size, y_size) / 5)
 
         # MINOR LINES ######
         if not kwargs['minor_is_tick']:
@@ -298,9 +330,9 @@ class ContourWriterBase(object):
         for lon in maj_lons:
             # Draw 'minor' tick lines dlat separation along the lon
             if kwargs['minor_is_tick']:
-                tick_lons = np.arange(lon - Dlon / 20.0,
-                                      lon + Dlon / 20.0,
-                                      Dlon / 50.0)
+                tick_lons = np.linspace(lon - Dlon / 20.0,
+                                        lon + Dlon / 20.0,
+                                        5)
 
                 for lat in min_lats:
                     lonlats = [(x, lat) for x in tick_lons]
@@ -354,9 +386,9 @@ class ContourWriterBase(object):
         for lat in maj_lats:
             # Draw 'minor' tick dlon separation along the lat
             if kwargs['minor_is_tick']:
-                tick_lats = np.arange(lat - Dlat / 20.0,
-                                      lat + Dlat / 20.0,
-                                      Dlat / 50.0)
+                tick_lats = np.linspace(lat - Dlat / 20.0,
+                                        lat + Dlat / 20.0,
+                                        5)
                 for lon in min_lons:
                     lonlats = [(lon, x) for x in tick_lats]
                     index_arrays, is_reduced = \
@@ -512,7 +544,7 @@ class ContourWriterBase(object):
 
         """
         try:
-            proj4_string = area_def.proj4_string
+            proj4_string = area_def.proj_str
             area_extent = area_def.area_extent
         except AttributeError:
             proj4_string = area_def[0]
@@ -619,7 +651,7 @@ class ContourWriterBase(object):
 
         if type(level) not in (list,):
             level = range(1,level+1)
-                        
+
         for i in level:
 
             # One shapefile per level
@@ -644,22 +676,12 @@ class ContourWriterBase(object):
                 yield shape
 
     def _finalize(self, draw):
-        """Do any need finalization of the drawing
-        """
+        """Do any need finalization of the drawing."""
 
         pass
 
-    def add_overlay_from_config(self, config_file, area_def):
-        """Create and return a transparent image adding all the overlays contained in a configuration file.
-
-        :Parameters:
-            config_file : str
-                Configuration file name
-            area_def : object
-                Area Definition of the creating image
-
-        """
-
+    def _config_to_dict(self, config_file):
+        """Convert a config file to a dict."""
         config = configparser.ConfigParser()
         try:
             with open(config_file, 'r'):
@@ -673,58 +695,79 @@ class ContourWriterBase(object):
             logger.error("Error in %s", str(config_file))
             raise
 
+        SECTIONS = ['cache', 'coasts', 'rivers', 'borders', 'cities', 'grid']
+        overlays = {}
+        for section in config.sections():
+            if section in SECTIONS:
+                overlays[section] = {}
+                for option in config.options(section):
+                    val = config.get(section, option)
+                    try:
+                        overlays[section][option] = ast.literal_eval(val)
+                    except ValueError:
+                        overlays[section][option] = val
+        return overlays
+
+    def add_overlay_from_dict(self, overlays, area_def, cache_epoch=None, background=None):
+        """Create and return a transparent image adding all the overlays contained in the `overlays` dict.
+
+        :Parameters:
+            overlays : dict
+                overlays configuration
+            area_def : object
+                Area Definition of the creating image
+            cache_epoch: seconds since epoch
+                The latest time allowed for cache the cache file. If the cache file is older than this (mtime),
+                the cache should be regenerated.
+            background: pillow image instance
+                The image on which to write the overlays on. If it's None (default),
+                a new image is created, otherwise the provide background is use
+                an change *in place*.
+
+
+            The keys in `overlays` that will be taken into account are:
+            cache, coasts, rivers, borders, cities, grid
+
+            For all of them except `cache`, the items are the same as the corresponding
+            functions in pycoast, so refer to the docstrings of these functions
+            (add_coastlines, add_rivers, add_borders, add_grid, add_cities).
+            For cache, two parameters are configurable: `file` which specifies the directory
+            and the prefix of the file to save the caches decoration to
+            (for example /var/run/black_coasts_red_borders), and `regenerate` that can be
+            True or False (default) to force the overwriting of an already cached file.
+
+        """
+
         # Cache management
         cache_file = None
-        if config.has_section('cache'):
-            config_file_name, config_file_extention = \
-                os.path.splitext(config_file)
-            cache_file = (config.get('cache', 'file') + '_' +
+        if 'cache' in overlays:
+            cache_file = (overlays['cache']['file'] + '_' +
                           area_def.area_id + '.png')
 
             try:
-                configTime = os.path.getmtime(config_file)
-                cacheTime = os.path.getmtime(cache_file)
+                config_time = cache_epoch
+                cache_time = os.path.getmtime(cache_file)
                 # Cache file will be used only if it's newer than config file
-                if configTime < cacheTime:
+                if ((config_time is not None and config_time < cache_time)
+                        and not overlays['cache'].get('regenerate', False)):
                     foreground = Image.open(cache_file)
                     logger.info('Using image in cache %s', cache_file)
+                    if background is not None:
+                        background.paste(foreground, mask=foreground.split()[-1])
                     return foreground
                 else:
-                    logger.info("Cache file is not used "
-                                "because config file has changed")
+                    logger.info("Regenerating cache file.")
             except OSError:
-                logger.info("New overlay image will be saved in cache")
-
-        x_size = area_def.x_size
-        y_size = area_def.y_size
-        foreground = Image.new('RGBA', (x_size, y_size), (0, 0, 0, 0))
-
-        # Lines (coasts, rivers, borders) management
-        prj = Proj(area_def.proj4_string)
-        if prj.is_latlong():
-            x_ll, y_ll = prj(area_def.area_extent[0], area_def.area_extent[1])
-            x_ur, y_ur = prj(area_def.area_extent[2], area_def.area_extent[3])
-            x_resolution = (x_ur - x_ll) / x_size
-            y_resolution = (y_ur - y_ll) / y_size
-        else:
-            x_resolution = ((area_def.area_extent[2] -
-                             area_def.area_extent[0]) /
-                            x_size)
-            y_resolution = ((area_def.area_extent[3] -
-                             area_def.area_extent[1]) /
-                            y_size)
-        res = min(x_resolution, y_resolution)
-
-        if res > 25000:
-            default_resolution = "c"
-        elif res > 5000:
-            default_resolution = "l"
-        elif res > 1000:
-            default_resolution = "i"
-        elif res > 200:
-            default_resolution = "h"
+                logger.info("No overlay image found, new overlay image will be saved in cache.")
+
+        x_size = area_def.width
+        y_size = area_def.height
+        if cache_file is None and background is not None:
+            foreground = background
         else:
-            default_resolution = "f"
+            foreground = Image.new('RGBA', (x_size, y_size), (0, 0, 0, 0))
+
+        default_resolution = get_resolution_from_area(area_def)
 
         DEFAULT = {'level': 1,
                    'outline': 'white',
@@ -736,18 +779,9 @@ class ContourWriterBase(object):
                    'y_offset': 0,
                    'resolution': default_resolution}
 
-        SECTIONS = ['coasts', 'rivers', 'borders', 'cities']
-        overlays = {}
-
-        for section in config.sections():
-            if section in SECTIONS:
-                overlays[section] = {}
-                for option in config.options(section):
-                    overlays[section][option] = config.get(section, option)
-
         is_agg = self._draw_module == "AGG"
 
-        # Coasts
+        # Coasts, rivers, borders
         for section, fun in zip(['coasts', 'rivers', 'borders'],
                                 [self.add_coastlines,
                                  self.add_rivers,
@@ -795,14 +829,63 @@ class ContourWriterBase(object):
                             font_size, pt_size, outline, box_outline,
                             box_opacity)
 
+        if 'grid' in overlays:
+            lon_major = float(overlays['grid'].get('lon_major', 10.0))
+            lat_major = float(overlays['grid'].get('lat_major', 10.0))
+            lon_minor = float(overlays['grid'].get('lon_minor', 2.0))
+            lat_minor = float(overlays['grid'].get('lat_minor', 2.0))
+            font = overlays['grid'].get('font', None)
+            font_size = int(overlays['grid'].get('font_size', 10))
+
+            write_text = overlays['grid'].get('write_text', True)
+            if isinstance(write_text, str):
+                write_text = write_text.lower() in ['true', 'yes', '1', 'on']
+            outline = overlays['grid'].get('outline', 'white')
+            if isinstance(font, str):
+                if is_agg:
+                    from aggdraw import Font
+                    font = Font(outline, font, size=font_size)
+                else:
+                    from PIL.ImageFont import truetype
+                    font = truetype(font, font_size)
+            fill = overlays['grid'].get('fill', None)
+            minor_outline = overlays['grid'].get('minor_outline', 'white')
+            minor_is_tick = overlays['grid'].get('minor_is_tick',
+                                                 'true').lower() in \
+                ['true', 'yes', '1']
+            lon_placement = overlays['grid'].get('lon_placement', 'tb')
+            lat_placement = overlays['grid'].get('lat_placement', 'lr')
+
+            self.add_grid(foreground, area_def, (lon_major, lat_major),
+                          (lon_minor, lat_minor),
+                          font=font, write_text=write_text, fill=fill,
+                          outline=outline, minor_outline=minor_outline,
+                          minor_is_tick=minor_is_tick,
+                          lon_placement=lon_placement,
+                          lat_placement=lat_placement)
+
         if cache_file is not None:
             try:
                 foreground.save(cache_file)
             except IOError as e:
                 logger.error("Can't save cache: %s", str(e))
-
+            if background is not None:
+                background.paste(foreground, mask=foreground.split()[-1])
         return foreground
 
+    def add_overlay_from_config(self, config_file, area_def, background=None):
+        """Create and return a transparent image adding all the overlays contained in a configuration file.
+
+        :Parameters:
+            config_file : str
+                Configuration file name
+            area_def : object
+                Area Definition of the creating image
+
+        """
+        overlays = self._config_to_dict(config_file)
+        return self.add_overlay_from_dict(overlays, area_def, os.path.getmtime(config_file), background)
+
     def add_cities(self, image, area_def, citylist, font_file, font_size,
                    ptsize, outline, box_outline, box_opacity, db_root_path=None):
         """Add cities (point and name) to a PIL image object
@@ -814,7 +897,7 @@ class ContourWriterBase(object):
             raise ValueError("'db_root_path' must be specified to use this method")
 
         try:
-            proj4_string = area_def.proj4_string
+            proj4_string = area_def.proj_str
             area_extent = area_def.area_extent
         except AttributeError:
             proj4_string = area_def[0]


=====================================
pycoast/tests/coasts_and_grid.ini
=====================================
@@ -0,0 +1,13 @@
+[coasts]
+level = 4
+resolution = l
+outline = white
+
+[grid]
+write_text = False
+lon_major = 10.0
+lat_major = 10.0
+lon_minor = 2.0
+lat_minor = 2.0
+minor_outline = blue
+outline = blue


=====================================
pycoast/tests/coasts_and_grid_agg.ini
=====================================
@@ -0,0 +1,18 @@
+[coasts]
+level = 4
+resolution = l
+outline = white
+
+[grid]
+write_text = True
+lon_major = 10.0
+lat_major = 10.0
+lon_minor = 2.0
+lat_minor = 2.0
+minor_outline = blue
+outline = blue
+lon_placement = tblr
+lat_placement = 
+font = pycoast/tests/test_data/DejaVuSerif.ttf
+font_size = 10
+


=====================================
pycoast/tests/contours_europe_alpha.png
=====================================
Binary files /dev/null and b/pycoast/tests/contours_europe_alpha.png differ


=====================================
pycoast/tests/dateline_boundary_cross.png
=====================================
Binary files a/pycoast/tests/dateline_boundary_cross.png and b/pycoast/tests/dateline_boundary_cross.png differ


=====================================
pycoast/tests/dateline_cross.png
=====================================
Binary files a/pycoast/tests/dateline_cross.png and b/pycoast/tests/dateline_cross.png differ


=====================================
pycoast/tests/grid_europe.png
=====================================
Binary files a/pycoast/tests/grid_europe.png and b/pycoast/tests/grid_europe.png differ


=====================================
pycoast/tests/grid_europe_agg.png
=====================================
Binary files a/pycoast/tests/grid_europe_agg.png and b/pycoast/tests/grid_europe_agg.png differ


=====================================
pycoast/tests/grid_europe_agg_txt.png
=====================================
Binary files a/pycoast/tests/grid_europe_agg_txt.png and b/pycoast/tests/grid_europe_agg_txt.png differ


=====================================
pycoast/tests/grid_geos.png
=====================================
Binary files a/pycoast/tests/grid_geos.png and b/pycoast/tests/grid_geos.png differ


=====================================
pycoast/tests/grid_geos_agg.png
=====================================
Binary files a/pycoast/tests/grid_geos_agg.png and b/pycoast/tests/grid_geos_agg.png differ


=====================================
pycoast/tests/grid_germ.png
=====================================
Binary files /dev/null and b/pycoast/tests/grid_germ.png differ


=====================================
pycoast/tests/grid_nh.png
=====================================
Binary files a/pycoast/tests/grid_nh.png and b/pycoast/tests/grid_nh.png differ


=====================================
pycoast/tests/grid_nh_agg.png
=====================================
Binary files a/pycoast/tests/grid_nh_agg.png and b/pycoast/tests/grid_nh_agg.png differ


=====================================
pycoast/tests/test_data/test_config.ini
=====================================
@@ -0,0 +1,12 @@
+[coasts]
+level=4
+resolution=l
+
+[borders]
+outline=(255, 0, 0)
+resolution=c
+
+[rivers]
+level=5
+outline=blue
+resolution=c


=====================================
pycoast/tests/test_pycoast.py
=====================================
@@ -22,7 +22,7 @@ import unittest
 
 import numpy as np
 from PIL import Image, ImageFont
-
+import time
 
 def tmp(f):
     f.tmp = True
@@ -68,6 +68,7 @@ def fft_metric(data1, data2, max_value=0.1):
 gshhs_root_dir = os.path.join(os.path.dirname(__file__), 'test_data', 'gshhs')
 test_file = 'test_image.png'
 grid_file = 'test_grid.png'
+p_file_coasts = 'test_coasts_p_mode.png'
 
 
 class TestPycoast(unittest.TestCase):
@@ -76,10 +77,13 @@ class TestPycoast(unittest.TestCase):
         img = Image.new('RGB', (640, 480))
         img.save(test_file)
         img.save(grid_file)
+        img_p = Image.new('P', (640, 480))
+        img_p.save(p_file_coasts)
 
     def tearDown(self):
         os.remove(test_file)
         os.remove(grid_file)
+        os.remove(p_file_coasts)
 
 
 class TestPIL(TestPycoast):
@@ -167,6 +171,32 @@ class TestPIL(TestPycoast):
         res = np.array(img)
         self.assertTrue(fft_metric(grid_data, res), 'Writing of grid failed')
 
+    def test_grid_germ(self):
+        """Check that issue #26 is fixed."""
+        from pycoast import ContourWriterPIL
+        result_file = os.path.join(os.path.dirname(__file__), 'grid_germ.png')
+        grid_img = Image.open(result_file)
+        grid_data = np.array(grid_img)
+        img = Image.new('RGB', (1024, 1024))
+        proj4_string = \
+            '+proj=stere +ellps=bessel +lat_0=90.0 +lon_0=5.0 +lat_ts=50.0 +a=6378144.0 +b=6356759.0'
+        area_extent = [-155100.436345, -4441495.37946, 868899.563655, -3417495.37946]
+
+        area_def = (proj4_string, area_extent)
+
+        cw = ContourWriterPIL(gshhs_root_dir)
+
+        cw.add_coastlines(img, area_def, resolution='l', level=4)
+        font = ImageFont.truetype(os.path.join(os.path.dirname(__file__),
+                                               'test_data', 'DejaVuSerif.ttf'),
+                                  16)
+        cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0),
+                    font=font, fill='yellow', write_text=True,
+                    outline='red', minor_outline='white')
+
+        res = np.array(img)
+        self.assertTrue(fft_metric(grid_data, res), 'Writing of grid to germ failed')
+
     def test_grid_geos(self):
         from pycoast import ContourWriterPIL
         geos_img = Image.open(
@@ -359,6 +389,29 @@ class TestPIL(TestPycoast):
         self.assertTrue(
             fft_metric(grid_data, res), 'Writing of Brazil shapefiles failed')
 
+    def test_config_file_coasts_and_grid(self):
+        from pycoast import ContourWriterPIL
+        from pyresample.geometry import AreaDefinition
+        overlay_config = os.path.join(os.path.dirname(__file__),
+                                      "coasts_and_grid.ini")
+        grid_img = Image.open(os.path.join(os.path.dirname(__file__),
+                                           'grid_nh.png'))
+        grid_data = np.array(grid_img)
+        proj_dict = {'proj': 'laea', 'lat_0': 90.0, 'lon_0': 0.0,
+                     'a': 6371228.0, 'units': 'm'}
+        area_extent = (-5326849.0625, -5326849.0625,
+                       5326849.0625, 5326849.0625)
+        area_def = AreaDefinition('nh', 'nh', 'nh', proj_dict, 425, 425,
+                                  area_extent)
+
+        cw = ContourWriterPIL(gshhs_root_dir)
+        overlay = cw.add_overlay_from_config(overlay_config, area_def)
+        img = Image.new('RGB', (425, 425))
+        img.paste(overlay, mask=overlay)
+        res = np.array(img)
+        self.assertTrue(fft_metric(grid_data, res),
+                        'Writing of nh grid failed')
+
 
 class TestPILAGG(TestPycoast):
 
@@ -624,12 +677,161 @@ class TestPILAGG(TestPycoast):
         self.assertTrue(
             fft_metric(grid_data, res), 'Writing of Brazil shapefiles failed')
 
+    @unittest.skip("All kwargs are not supported, so can't create equal results")
+    def test_config_file_coasts_and_grid(self):
+        from pycoast import ContourWriterAGG
+        from pyresample.geometry import AreaDefinition
+        overlay_config = os.path.join(os.path.dirname(__file__),
+                                      "coasts_and_grid_agg.ini")
+        grid_img = Image.open(os.path.join(os.path.dirname(__file__),
+                                           'grid_nh_agg.png'))
+        grid_data = np.array(grid_img)
+        proj_dict = {'proj': 'laea', 'lat_0': 90.0, 'lon_0': 0.0,
+                     'a': 6371228.0, 'units': 'm'}
+        area_extent = (-5326849.0625, -5326849.0625,
+                       5326849.0625, 5326849.0625)
+        area_def = AreaDefinition('nh', 'nh', 'nh', proj_dict, 425, 425,
+                                  area_extent)
+
+        cw = ContourWriterAGG(gshhs_root_dir)
+        overlay = cw.add_overlay_from_config(overlay_config, area_def)
+        img = Image.new('RGB', (425, 425))
+        img.paste(overlay, mask=overlay)
+
+        res = np.array(img)
+        self.assertTrue(fft_metric(grid_data, res),
+                        'Writing of nh grid failed')
+
+    def test_coastlines_convert_to_rgba_agg(self):
+        from pycoast import ContourWriterAGG
+        proj4_string = \
+            '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84'
+        area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1)
+        area_def = (proj4_string, area_extent)
+
+        cw = ContourWriterAGG(gshhs_root_dir)
+        cw.add_coastlines_to_file(p_file_coasts, area_def, resolution='l', level=4)
+
+        img = Image.open(p_file_coasts)
+        image_mode = img.mode
+        img.close()
+
+        self.assertTrue(image_mode == 'RGBA', 'Conversion to RGBA failed.')
+
+
+class FakeAreaDef():
+    """A fake area definition object."""
+
+    def __init__(self, proj4_string, area_extent, x_size, y_size):
+        self.proj_str = proj4_string
+        self.area_extent = area_extent
+        self.width = x_size
+        self.height = y_size
+        self.area_id = 'fakearea'
+
+
+class TestFromConfig(TestPycoast):
+    """Test burning overlays from a config file."""
+
+    def test_foreground(self):
+        """Test generating a transparent foreground."""
+        from pycoast import ContourWriterPIL
+        euro_img = Image.open(os.path.join(os.path.dirname(__file__),
+                                           'contours_europe_alpha.png'))
+        euro_data = np.array(euro_img)
+
+        # img = Image.new('RGB', (640, 480))
+        proj4_string = \
+            '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84'
+        area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1)
+        area_def = FakeAreaDef(proj4_string, area_extent, 640, 480)
+        cw = ContourWriterPIL(gshhs_root_dir)
+        config_file = os.path.join(os.path.dirname(__file__), 'test_data', 'test_config.ini')
+        img = cw.add_overlay_from_config(config_file, area_def)
+
+        res = np.array(img)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+
+        overlays = {'coasts': {'level': 4, 'resolution': 'l'},
+                    'borders': {'outline': (255, 0, 0), 'resolution': 'c'},
+                    'rivers': {'outline': 'blue', 'resolution': 'c', 'level': 5}}
+
+        img = cw.add_overlay_from_dict(overlays, area_def)
+        res = np.array(img)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+
+    def test_cache(self):
+        """Test generating a transparent foreground and cache it."""
+        from pycoast import ContourWriterPIL
+        from tempfile import gettempdir
+        euro_img = Image.open(os.path.join(os.path.dirname(__file__),
+                                           'contours_europe_alpha.png'))
+        euro_data = np.array(euro_img)
+
+        # img = Image.new('RGB', (640, 480))
+        proj4_string = \
+            '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84'
+        area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1)
+        area_def = FakeAreaDef(proj4_string, area_extent, 640, 480)
+        cw = ContourWriterPIL(gshhs_root_dir)
+
+        tmp = gettempdir()
+
+        overlays = {'cache': {'file': os.path.join(tmp, 'pycoast_cache')},
+                    'coasts': {'level': 4, 'resolution': 'l'},
+                    'borders': {'outline': (255, 0, 0), 'resolution': 'c'},
+                    'rivers': {'outline': 'blue', 'resolution': 'c', 'level': 5}}
+
+        cache_filename = os.path.join(tmp, 'pycoast_cache_fakearea.png')
+        img = cw.add_overlay_from_dict(overlays, area_def)
+        res = np.array(img)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+        self.assertTrue(os.path.isfile(cache_filename))
+
+        current_time = time.time()
+
+        img = cw.add_overlay_from_dict(overlays, area_def, current_time)
+
+        mtime = os.path.getmtime(cache_filename)
+
+        self.assertGreater(mtime, current_time)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+
+        img = cw.add_overlay_from_dict(overlays, area_def, current_time)
+
+        self.assertEqual(os.path.getmtime(cache_filename), mtime)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+        overlays['cache']['regenerate'] = True
+        img = cw.add_overlay_from_dict(overlays, area_def)
+
+        self.assertNotEqual(os.path.getmtime(cache_filename), mtime)
+        self.assertTrue(fft_metric(euro_data, res),
+                        'Writing of contours failed')
+        os.remove(os.path.join(tmp, 'pycoast_cache_fakearea.png'))
+
+    def test_get_resolution(self):
+        """Get the automagical resolution computation."""
+        from pycoast import get_resolution_from_area
+        proj4_string = \
+            '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84'
+        area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1)
+        area_def = FakeAreaDef(proj4_string, area_extent, 640, 480)
+        self.assertEqual(get_resolution_from_area(area_def), 'l')
+        area_def = FakeAreaDef(proj4_string, area_extent, 6400, 4800)
+        self.assertEqual(get_resolution_from_area(area_def), 'h')
+
 
 def suite():
     loader = unittest.TestLoader()
     mysuite = unittest.TestSuite()
     mysuite.addTest(loader.loadTestsFromTestCase(TestPIL))
     mysuite.addTest(loader.loadTestsFromTestCase(TestPILAGG))
+    mysuite.addTest(loader.loadTestsFromTestCase(TestFromConfig))
 
     return mysuite
 


=====================================
pycoast/version.py
=====================================
@@ -23,9 +23,9 @@ def get_keywords():
     # setup.py/versioneer.py will grep for the variable names, so they must
     # each be defined on a line of their own. _version.py will just call
     # get_keywords().
-    git_refnames = " (HEAD -> master, tag: v1.2.3)"
-    git_full = "eaddef8f6c84867137c6e32d5a89e629fa012fc2"
-    git_date = "2019-06-06 10:16:30 -0500"
+    git_refnames = " (HEAD -> master, tag: v1.3.0)"
+    git_full = "60a725edca4b3896bcbba8ff67704041fd0e382b"
+    git_date = "2019-10-25 08:39:57 +0200"
     keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
     return keywords
 


=====================================
setup.py
=====================================
@@ -19,6 +19,8 @@ from setuptools import setup
 import versioneer
 
 requires = ['aggdraw', 'pyshp', 'numpy', 'pyproj', 'pillow', 'six']
+tests_require = ['aggdraw', 'pyshp', 'numpy', 'pyproj', 'pillow', 'six',
+                 'pyresample']
 
 with open('README', 'r') as readme_file:
     long_description = readme_file.read()
@@ -32,6 +34,7 @@ setup(name='pycoast',
       author_email='esn at dmi.dk',
       packages=['pycoast', 'pycoast.tests'],
       install_requires=requires,
+      tests_require=tests_require,
       test_suite='pycoast.tests.test_pycoast.suite',
       zip_safe=False,
       classifiers=[



View it on GitLab: https://salsa.debian.org/debian-gis-team/pycoast/commit/f59edc8c9029a8e25c32c23fbd67a88b25f6c5c0

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/pycoast/commit/f59edc8c9029a8e25c32c23fbd67a88b25f6c5c0
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20191029/1b433b75/attachment-0001.html>


More information about the Pkg-grass-devel mailing list