Giant blob of minor changes
[dotfiles/.git] / .config / GIMP / 2.10 / plug-ins / plugin-uncrop.py
diff --git a/.config/GIMP/2.10/plug-ins/plugin-uncrop.py b/.config/GIMP/2.10/plug-ins/plugin-uncrop.py
new file mode 100755 (executable)
index 0000000..e50f3f4
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+
+'''
+Gimp plugin "Uncrop"
+
+Increase image/canvas size and synthesize outer band from edge of original.
+
+Author:
+lloyd konneker, lkk
+
+Version:
+1.0 lkk 5/15/2009 Initial version in scheme, released to Gimp Registry.
+1.1 lkk 9/21/2009 Translate to python.
+
+License:
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+The GNU Public License is available at
+http://www.gnu.org/copyleft/gpl.html
+
+
+The effect for users:  
+widens the field of view, maintaining perspective of original
+Should be undoable, except for loss of selection.
+Should work on any image type, any count of layers and channels (although only active layer is affected.)
+
+Programming notes:
+Scheme uses - in names, python uses _
+Programming devt. cycle: 
+Initial creation: cp foo.py ~/.gimp-2.6/scripts, chmod +x, start gimp
+Refresh:  just copy, no need to restart gimp if the pdb registration is unchanged
+
+IN: Nothing special.  The selection is immaterial but is not preserved.
+OUT larger layer and image.  All other layers not enlarged.
+'''
+
+from gimpfu import *
+
+gettext.install("resynthesizer", gimp.locale_directory, unicode=True)
+    
+def resizeImageCentered(image, percentEnlarge):
+    # resize and center image by percent (converted to pixel units)
+    deltaFraction = (percentEnlarge / 100) + 1.0
+    priorWidth = pdb.gimp_image_width(image)
+    priorHeight = pdb.gimp_image_height(image)
+    deltaWidth = priorWidth * deltaFraction
+    deltaHeight = priorHeight * deltaFraction
+    centeredOffX = (deltaWidth - priorWidth)/  2 
+    centeredOffY = (deltaHeight - priorHeight) / 2 
+    pdb.gimp_image_resize(image, deltaWidth, deltaHeight, centeredOffX, centeredOffY)
+    #if not pdb.gimp_image_resize(image, deltaWidth, deltaHeight, centeredOffX, centeredOffY):
+    #    raise RuntimeError, "Failed resize"
+        
+def shrinkSelectionByPercent(image, percent):
+    # shrink selection by percent (converted to pixel units)
+    deltaFraction = percent / 100
+    # convert to pixel dimensions
+    priorWidth = pdb.gimp_image_width(image)
+    priorHeight = pdb.gimp_image_height(image)
+    deltaWidth = priorWidth * deltaFraction
+    deltaHeight = priorHeight * deltaFraction
+    # !!! Note total shrink percentage is halved (width of band is percentage/2)
+    maxDelta = max(deltaWidth, deltaHeight) / 2 
+    
+    pdb.gimp_selection_shrink(image, maxDelta)
+    #if not pdb.gimp_selection_shrink(image, maxDelta):
+    #    raise RuntimeError,  "Failed shrink selection"
+
+
+def uncrop(orgImage, drawable, percentEnlargeParam=10):
+    '''
+    Create frisket stencil selection in a temp image to pass as source (corpus) to plugin resynthesizer,
+    which does the substantive work.
+    '''
+    
+    if not pdb.gimp_item_is_layer(drawable):
+      pdb.gimp_message(_("A layer must be active, not a channel."))
+      return
+      
+    pdb.gimp_image_undo_group_start(orgImage)
+    
+    # copy original into temp for later use
+    tempImage = pdb.gimp_image_duplicate(orgImage)
+    if not tempImage:
+        raise RuntimeError, "Failed duplicate image"
+    
+    '''
+    Prepare target: enlarge canvas and select the new, blank outer ring
+    '''
+    
+    # Save original bounds to later select outer band
+    pdb.gimp_selection_all(orgImage)
+    selectAllPrior = pdb.gimp_selection_save(orgImage)
+    # Resize image alone doesn't resize layer, so resize layer also
+    resizeImageCentered(orgImage, percentEnlargeParam)
+    pdb.gimp_layer_resize_to_image_size(drawable)
+    pdb.gimp_image_select_item(orgImage, CHANNEL_OP_REPLACE, selectAllPrior)
+    # select outer band, the new blank canvas.
+    pdb.gimp_selection_invert(orgImage)
+    # Assert target image is ready.
+                  
+    '''
+    Prepare source (corpus) layer, a band at edge of original, in a dupe.
+    Note the width of corpus band is same as width of enlargement band.
+    '''
+    # Working with the original size.
+    # Could be alpha channel transparency
+    workLayer = pdb.gimp_image_get_active_layer(tempImage)
+    if not workLayer:
+        raise RuntimeError, "Failed get active layer"
+    # Select outer band:  select all, shrink
+    pdb.gimp_selection_all(tempImage)
+    shrinkSelectionByPercent(tempImage, percentEnlargeParam)
+    pdb.gimp_selection_invert(tempImage)    # invert interior selection into a frisket
+    # Note that v1 resynthesizer required an inverted selection !!
+    # No need to crop corpus to save memory.
+      
+    # Note that the API hasn't changed but use_border param now has more values.
+    # !!! The crux: use_border param=5 means inside out direction
+    pdb.plug_in_resynthesizer(orgImage, drawable, 0,0,5, workLayer.ID, -1, -1, 0.0, 0.117, 16, 500)
+    
+    # Clean up. 
+    # Any errors now are moot.
+    pdb.gimp_selection_none(orgImage)
+    pdb.gimp_image_remove_channel(orgImage, selectAllPrior)
+    pdb.gimp_image_undo_group_end(orgImage)
+    pdb.gimp_displays_flush()
+    gimp.delete(tempImage)  # Comment out to debug corpus creation.
+
+
+register(
+  "python_fu_uncrop",
+  N_("Enlarge image by synthesizing a border that matches the edge, maintaining perspective.  Works best for small enlargement of natural edges. Undo a Crop instead, if possible! "),
+  "Requires separate resynthesizer plugin.",
+  "Lloyd Konneker",
+  "Copyright 2009 Lloyd Konneker",
+  "2009",
+  N_("Uncrop..."),
+  "RGB*, GRAY*",
+  [
+    (PF_IMAGE, "image",       "Input image", None),
+    (PF_DRAWABLE, "drawable", "Input drawable", None),
+    (PF_SLIDER, "percentEnlargeParam", _("Percent enlargement"), 10, (0, 100, 1))
+  ],
+  [],
+  uncrop,
+  menu="<Image>/Filters/Enhance",
+  domain=("resynthesizer", gimp.locale_directory)
+  )
+
+main()
+