[GRASS-SVN] r73329 - grass/trunk/lib/python/imaging

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Sep 14 13:41:30 PDT 2018


Author: wenzeslaus
Date: 2018-09-14 13:41:29 -0700 (Fri, 14 Sep 2018)
New Revision: 73329

Added:
   grass/trunk/lib/python/imaging/operations.py
Modified:
   grass/trunk/lib/python/imaging/Makefile
   grass/trunk/lib/python/imaging/README
Log:
pythonlib: add image file manipulation functions to imaging

Modified: grass/trunk/lib/python/imaging/Makefile
===================================================================
--- grass/trunk/lib/python/imaging/Makefile	2018-09-14 19:39:20 UTC (rev 73328)
+++ grass/trunk/lib/python/imaging/Makefile	2018-09-14 20:41:29 UTC (rev 73329)
@@ -7,7 +7,7 @@
 GDIR = $(PYDIR)/grass
 DSTDIR = $(GDIR)/imaging
 
-MODULES = images2avi images2gif images2ims images2swf
+MODULES = images2avi images2gif images2ims images2swf operations
 
 PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
 PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)

Modified: grass/trunk/lib/python/imaging/README
===================================================================
--- grass/trunk/lib/python/imaging/README	2018-09-14 19:39:20 UTC (rev 73328)
+++ grass/trunk/lib/python/imaging/README	2018-09-14 20:41:29 UTC (rev 73329)
@@ -1,12 +1,15 @@
 General
 =======
-This is a part of visvis library [1], specifically visvis.vvmovie.
-The files are from the visvis-1.8 version.
 
+This is a library for manipulating (non-geospatial) images in GRASS GIS.
+
+The images2*.py files are a part of visvis library [1], specifically
+visvis.vvmovie. The files are from the visvis-1.8 version.
+
 [1] https://code.google.com/p/visvis/
 
-Changes
-=======
+Changes to visvis
+=================
 In images2avi, the image format for temporary files is changed
 from JPG to PNG, to improve the resulting AVI. This makes the size larger,
 however the JPG format is unsuitable for maps in general.
@@ -33,7 +36,7 @@
      
 Questions
 =========
-Should we make these files PEP8 compliant? This would make
+Should we make the visvis files PEP8 compliant? This would make
 merging of possible changes from visvis more difficult.
 
 

Added: grass/trunk/lib/python/imaging/operations.py
===================================================================
--- grass/trunk/lib/python/imaging/operations.py	                        (rev 0)
+++ grass/trunk/lib/python/imaging/operations.py	2018-09-14 20:41:29 UTC (rev 73329)
@@ -0,0 +1,180 @@
+"""
+Image non-geospatial operations and manipulations
+
+Note: Functions in this module are experimental and are not considered
+a stable API, i.e. may change in future releases of GRASS GIS.
+
+It heavily relies on PIL but unlike PIL, the functions operate on
+files instead of PIL Image objects (which are used internally).
+These functions are convenient for post-processing outputs from GRASS
+modules, e.g. after rendering. However, if you have multiple operations
+you may want to consider using PIL directly for efficiency (to avoid
+writing and reading from the files).
+
+Usage
+=====
+
+Use keyword arguments for all parameters other than those for input,
+output, and format. All function provide reasonable defaults if possible,
+but note that they may not be applicable to you case or when developing
+a general tool.
+
+>>> import grass.imaging.operations as iop
+
+>>> # replace white color in the image by 100% transparency
+>>> iop.change_rbg_to_transparent("map.png", color=(255, 255, 255))
+
+>>> # crop the image in place
+>>> iop.crop_image("map.png")
+
+>>> # create a new image with inverted colors of the original image
+>>> iop.invert_image_colors("map.png", "map_inverted.png")
+
+>>> # create a thumbnail of the original image
+>>> iop.thumbnail_image("map.png", "map_thumbnail.png", size=(64, 64))
+
+Error handling
+==============
+
+When PIL or a required submodule is not available, a RuntimeError
+exception is raised with a message mentioning the missing dependency.
+Additionally, any of the exceptions raised by PIL may be raised too,
+for example, when the file is not found.
+
+Authors, copyright and license
+==============================
+
+(C) 2018 by Vaclav Petras and the GRASS Development Team
+
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+.. sectionauthor:: Vaclav Petras <wenzeslaus gmail com>
+"""
+
+
+# import similar to what is in visvis
+try:
+    import PIL
+    from PIL import Image
+    PILLOW = True
+    try:
+        from PIL import PILLOW_VERSION  # pylint: disable=unused-import
+    except ImportError:
+        PILLOW = False
+    try:
+        import PIL.ImageOps as ImageOps
+    except ImportError:
+        ImageOps = None
+except ImportError:
+    PIL = None
+
+
+def crop_image(input_file, output_file=None, format=None):
+    """Crop to non-zero area of the image
+
+    :param input_file: Name of the file to manipulate
+    :param output_file: filename for the new file (same as input by default)
+    :param format: format to be used new file (if different from extension)
+    """
+    if PIL is None:
+        raise RuntimeError(_("Install PIL or Pillow to use this function"))
+    if not output_file:
+        output_file = input_file
+    img = Image.open(input_file)
+    box = img.getbbox()
+    cropped_image = img.crop(box)
+    cropped_image.save(output_file, format)
+
+
+def thumbnail_image(input_file, output_file=None, size=(200, 200),
+                    format=None):
+    """Create a thumbnail of an image
+
+    The image aspect ratio is kept and its height and width are adjusted
+    accordingly to fit the ``size`` parameter.
+
+    :param input_file: Name of the file to manipulate
+    :param size: Size of the new image in pixels as tuple
+    :param output_file: filename for the new file (same as input by default)
+    :param format: format to be used new file (if different from extension)
+    """
+    if PIL is None:
+        raise RuntimeError(_("Install PIL or Pillow to use this function"))
+    if not output_file:
+        output_file = input_file
+    img = Image.open(input_file)
+    img.thumbnail(size, Image.ANTIALIAS)
+    img.save(output_file, format)
+
+
+def change_rbg_to_transparent(input_file, output_file=None, color='white',
+                              alpha=0, format=None):
+    """Make a specified RGB color in the image transparent
+
+    The color is specified as a RGB tuple (triplet) or string 'white'
+    or 'black'. Note that GRASS color names are not supported.
+    The white (255, 255, 255) is replaced by default but each application
+    is encouraged to consider color to use and explicitly specify it.
+
+    :param input_file: Name of the file to manipulate
+    :param color: Color to be replaced by transparency (tuple of three ints)
+    :param alpha: Level of opacity (0 fully transparent, 255 fully opaque)
+    :param output_file: filename for the new file (same as input by default)
+    :param format: format to be used new file (if different from extension)
+    """
+    if PIL is None:
+        raise RuntimeError(_("Install PIL or Pillow to use this function"))
+    if color == 'white':
+        rgb = (255, 255, 255)
+    elif color == 'black':
+        rgb = (0, 0, 0)
+    else:
+        rgb = color  # pylint: disable=redefined-variable-type
+    if not output_file:
+        output_file = input_file
+    img = Image.open(input_file)
+    img = img.convert("RGBA")
+    old_data = img.getdata()
+    new_data = []
+    for item in old_data:
+        if item[0] == rgb[0] and item[1] == rgb[1] and item[2] == rgb[2]:
+            new_data.append((rgb[0], rgb[1], rgb[2], alpha))
+        else:
+            new_data.append(item)
+    img.putdata(new_data)
+    img.save(output_file, format)
+
+
+def invert_image_colors(input_file, output_file=None, format=None):
+    """Invert colors in the image
+
+    The alpha channel, if present, is untouched by this function.
+
+    :param input_file: Name of the file to manipulate
+    :param output_file: filename for the new file (same as input by default)
+    :param format: format to be used new file (if different from extension)
+    """
+    if PIL is None:
+        raise RuntimeError(_("Install PIL or Pillow to use this function"))
+    if ImageOps is None:
+        raise RuntimeError(_("Install a newer version of PIL or Pillow to"
+                             " use this function (missing ImageOps module)"))
+    if not output_file:
+        output_file = input_file
+    original_img = Image.open(input_file)
+    # according to documentation (3.0.x) the module can work only on RGB
+    # so we need to specifically take care of transparency if present
+    if original_img.mode == 'RGBA':
+        # split into bands
+        red1, green1, blue1, alpha = original_img.split()
+        rgb_img = Image.merge('RGB', (red1, green1, blue1))
+        # invert RGB
+        inverted_rgb_img = ImageOps.invert(rgb_img)
+        # put back the original alpha
+        red2, green2, blue2 = inverted_rgb_img.split()
+        new_image = Image.merge('RGBA', (red2, green2, blue2, alpha))
+    else:
+        new_image = ImageOps.invert(original_img)
+    new_image.save(output_file, format)


Property changes on: grass/trunk/lib/python/imaging/operations.py
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/x-python
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property


More information about the grass-commit mailing list