/usr/lib/gimp/2.0/plug-ins/plugin-heal-selection.py is in gimp-plugin-registry 7.20140602ubuntu3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | #!/usr/bin/env python
'''
Gimp plugin "Heal selection"
Copyright 2009 lloyd konneker (bootch at nc.rr.com)
Based on smart_remove.scm Copyright 2000 by Paul Harrison.
Version:
1.0 lloyd konneker lkk 9/21/2009 Initial version in python.
(See release notes for differences over P. Harrison's prior version in scheme language.)
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
'''
from gimpfu import *
gettext.install("resynthesizer", gimp.locale_directory, unicode=True)
debug = False
def heal_selection(timg, tdrawable, samplingRadiusParam=50, directionParam=0, orderParam=0):
'''
Create stencil selection in a temp image to pass as source (corpus) to plugin resynthesizer,
which does the substantive work.
'''
if pdb.gimp_selection_is_empty(timg):
pdb.gimp_message(_("You must first select a region to heal."))
return
pdb.gimp_image_undo_group_start(timg)
targetBounds = tdrawable.mask_bounds
# In duplicate image, create the sample (corpus).
# (I tried to use a temporary layer but found it easier to use duplicate image.)
tempImage = pdb.gimp_image_duplicate(timg)
if not tempImage:
raise RuntimeError, "Failed duplicate image"
# !!! The drawable can be a mask (grayscale channel), don't restrict to layer.
work_drawable = pdb.gimp_image_get_active_drawable(tempImage)
if not work_drawable:
raise RuntimeError, "Failed get active drawable"
'''
grow and punch hole, making a frisket iow stencil iow donut
'''
orgSelection = pdb.gimp_selection_save(tempImage) # save for later use
pdb.gimp_selection_grow(tempImage, samplingRadiusParam)
# ??? returns None , docs say it returns SUCCESS
# !!! Note that if selection is a bordering ring already, growing expanded it inwards.
# Which is what we want, to make a corpus inwards.
grownSelection = pdb.gimp_selection_save(tempImage)
# Cut hole where the original selection was, so we don't sample from it.
# !!! Note that gimp enums/constants are not prefixed with GIMP_
pdb.gimp_selection_combine(orgSelection, CHANNEL_OP_SUBTRACT)
'''
Selection (to be the corpus) is donut or frisket around the original target T
xxx
xTx
xxx
'''
# crop the temp image to size of selection to save memory and for directional healing!!
frisketBounds = grownSelection.mask_bounds
frisketLowerLeftX = frisketBounds[0]
frisketLowerLeftY = frisketBounds[1]
frisketUpperRightX = frisketBounds[2]
frisketUpperRightY = frisketBounds[3]
targetLowerLeftX = targetBounds[0]
targetLowerLeftY = targetBounds[1]
targetUpperRightX = targetBounds[2]
targetUpperRightY = targetBounds[3]
frisketWidth = frisketUpperRightX - frisketLowerLeftX
frisketHeight = frisketUpperRightY - frisketLowerLeftY
# User's choice of direction affects the corpus shape, and is also passed to resynthesizer plugin
if directionParam == 0: # all around
# Crop to the entire frisket
newWidth, newHeight, newLLX, newLLY = ( frisketWidth, frisketHeight,
frisketLowerLeftX, frisketLowerLeftY )
elif directionParam == 1: # sides
# Crop to target height and frisket width: XTX
newWidth, newHeight, newLLX, newLLY = ( frisketWidth, targetUpperRightY-targetLowerLeftY,
frisketLowerLeftX, targetLowerLeftY )
elif directionParam == 2: # above and below
# X Crop to target width and frisket height
# T
# X
newWidth, newHeight, newLLX, newLLY = ( targetUpperRightX-targetLowerLeftX, frisketHeight,
targetLowerLeftX, frisketLowerLeftY )
# Restrict crop to image size (condition of gimp_image_crop) eg when off edge of image
newWidth = min(pdb.gimp_image_width(tempImage) - newLLX, newWidth)
newHeight = min(pdb.gimp_image_height(tempImage) - newLLY, newHeight)
pdb.gimp_image_crop(tempImage, newWidth, newHeight, newLLX, newLLY)
# Encode two script params into one resynthesizer param.
# use border 1 means fill target in random order
# use border 0 is for texture mapping operations, not used by this script
if not orderParam :
useBorder = 1 # User wants NO order, ie random filling
elif orderParam == 1 : # Inward to corpus. 2,3,4
useBorder = directionParam+2 # !!! Offset by 2 to get past the original two boolean values
else:
# Outward from image center.
# 5+0=5 outward concentric
# 5+1=6 outward from sides
# 5+2=7 outward above and below
useBorder = directionParam+5
# Note that the old resynthesizer required an inverted selection !!
if debug:
try:
gimp.Display(tempImage)
gimp.displays_flush()
except RuntimeError: # thrown if non-interactive
pass
from time import sleep
sleep(2)
# Not necessary to restore image to initial condition of selection, activity,
# the original image should not have been changed,
# and the resynthesizer should only heal, not change selection.
# Note that the API hasn't changed but use_border param now has more values.
pdb.plug_in_resynthesizer(timg, tdrawable, 0,0, useBorder, work_drawable.ID, -1, -1, 0.0, 0.117, 16, 500)
# Clean up (comment out to debug)
gimp.delete(tempImage)
pdb.gimp_image_undo_group_end(timg)
register(
"python_fu_heal_selection",
N_("Heal the selection from surroundings as if using the heal tool."),
"Requires separate resynthesizer plugin.",
"Lloyd Konneker",
"2009 Lloyd Konneker", # Copyright
"2009",
N_("_Heal selection..."),
"RGB*, GRAY*",
[
(PF_IMAGE, "image", "Input image", None),
(PF_DRAWABLE, "drawable", "Input drawable", None),
(PF_INT, "samplingRadiusParam", _("Context sampling width (pixels):"), 50),
(PF_OPTION,"directionParam", _("Sample from:"),0,[_("All around"),_("Sides"),_("Above and below")]),
(PF_OPTION, "orderParam", _("Filling order:"), 0, [_("Random"),
_("Inwards towards center"), _("Outwards from center") ])
],
[],
heal_selection,
menu="<Image>/Filters/Enhance",
domain=("resynthesizer", gimp.locale_directory)
)
main()
|