#!/usr/bin/env python
#
# ==============================================================================
# GraduatedFilter.py V4 - (c) Berthold Hinz 2009
# ==============================================================================
#
# GRADUATED FILTER FOR THE GIMP
#
# ==============================================================================
# This script is the result of joint effort and inspiring discussion in the
# forum of www.meetthegimp.org. It was initiated by Luigi and includes smart
# suggestians and ideas of him and the forum members Rolf, di98jgu and
# mramshaw.
#
# ==============================================================================
# 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, version 3 of the License.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# ==============================================================================
from gimpfu import *
def GFilters(img, drw, filter, f_colour, softness, type, orientation):
## CONSTANTS
col_code={2:(0,255,255),3:(0,0,255),4:(210,105,30),5:(255,0,255),6:(0,128,0),7:(0,255,0),8:(128,0,0),9:(203,78,97),10:(0,0,128),11:(128,128,0),12:(255,165,0),13:(128,0,128),14:(255,0,0),15:(70,130,180),16:(237,140,25),17:(0,128,128),18:(111,78,55),19:(255,255,0)}
col_name={2:"aqua",3:"blue",4:"chocolate",5:"fuchsia",6:"green",7:"lime",8:"maroon",9:"mauve",10:"navy",11:"olive",12:"orange",13:"purple",14:"red",15:"steelblue",16:"sunset",17:"teal",18:"tobacco",19:"yellow"}
fgc = gimp.get_foreground()
bgc = gimp.get_background()
w=img.width
h=img.height
pdb.gimp_image_undo_group_start(img)
## CHECK REQUIREMENTS
numlayers=len(img.layers)
maskexists=pdb.gimp_layer_get_mask(img.layers[0])
if maskexists<>None:
m="There's already a mask for the lighter layer." + "\n"+"\n"+"The gradient can't be added."+"\n" + "Please remove the layer mask and run the script again! (Shortcut: Ctrl+F)"
gimp.message(m)
if numlayers<>2:
m="Invalid Number of layers!" + "\n"+"\n"+"Exactly 2 layers are necessary to use the Graduated Filters."+"\n" + "Please open two differently exposed images as layers (shortcut: CTRL+ALT+O) and run the script again! (Ctrl+F)"
gimp.message(m)
else:
## SORT LAYERS ACCORDING LIGHTNESS
drw=img.layers[0]
(mean, std_dev, median, pixels, count, percentile) = pdb.gimp_histogram (drw, HISTOGRAM_VALUE,0,255)
meanL0=mean
drw=img.layers[1]
(mean, std_dev, median, pixels, count, percentile) = pdb.gimp_histogram (drw, HISTOGRAM_VALUE,0,255)
meanL1=mean
if meanL1>meanL0:
pdb.gimp_image_raise_layer_to_top(img,drw)
img.layers[0].name="lighter image"
img.layers[1].name="darker image"
## APPPLY FILTER
if maskexists==None:
if filter==0:
f_colour=(0,0,0)
elif filter==1:
lname="custom colour"+" (adjust opacity)"
else:
f_colour=col_code[filter]
lname=col_name[filter]+" (adjust opacity)"
if filter>0:
if pdb.gimp_drawable_is_rgb(img.layers[0])==False:
pdb.gimp_image_convert_rgb(img)
m="Image conversion." + "\n" +"\n" + "Since you added colour to your grayscale image it was converted to RGB-mode."
gimp.message(m)
if type=="horizon":
guide_mode,guide_y,guide_m = guide_det(img)
if guide_mode==1:
horizon=guide_y
gnd_name="manual horizon:"
elif guide_mode==2:
gimp.message(guide_m)
else:
horizon=a_horizon(img,img.layers[1],h,w,3.0,0.5)
gnd_name="auto horizon:"
gnd_name=gnd_name+str(horizon) + "; softness:" + str(softness)
if orientation=="flipped":
gnd_name=gnd_name+"; flipped"
gnd_name=gnd_name+" (adjust opacity)"
## CALL FUNCTION TO CREATE FILTER
if type=="horizon":
make_gradient(img,img.layers[0],horizon,softness,orientation,filter,f_colour)
if type=="lightness":
make_lfilter(img,img.layers[0],softness,filter,f_colour)
gnd_name="lightness mode; softness:" + str(softness) + " (adjust opacity)"
l=0
if filter>0:
l=1
img.layers[0].name=lname
img.layers[l].name=gnd_name
## RESET
gimp.set_foreground(fgc)
gimp.set_background(bgc)
pdb.gimp_image_undo_group_end(img)
## AUTODETECTION HORIZON
def a_horizon(img,drw,h,w,resolution,prop_width):
hor=0
steps=int(h/resolution)
sel_h=resolution
sel_w=w*prop_width
sel_x=w*(1-prop_width)/2
sel_y=0
last_mv=0.0
curr_mv=0.0
diff_max=0.0
for i in xrange(steps-6):
sel_y=(i+3)*sel_h
pdb.gimp_rect_select(img, sel_x, sel_y, sel_w, sel_h, 2, False, 0)
(mean, std_dev, median, pixels, count, percentile) = pdb.gimp_histogram (drw, HISTOGRAM_VALUE,0,255)
if i>0:
last_mv=curr_mv
curr_mv=mean
diff=abs(curr_mv-last_mv)
if diff>diff_max and last_mv>0:
diff_max=diff
if i>1:
hor=sel_y+resolution
if hor<5 or hor>h-5:
hor=h
m="No horizon found!" + "\n"+"\n"+"Gradient will extend across the full height of the image. If this is not desired, undo the changes (Ctrl+Z), set the horizon manually by guide and run the script again! (Ctrl+F)"
gimp.message(m)
else:
pdb.gimp_image_add_hguide(img,hor)
pdb.gimp_selection_none(img)
return hor
## SEARCH FOR MANUALLY SET HORIZON
def guide_det(img):
guide_mode=0
guide_y=0
guide_m=""
guide_num_1 = pdb.gimp_image_find_next_guide(img, 0)
if guide_num_1<>0:
guide_or=pdb.gimp_image_get_guide_orientation(img,guide_num_1)
if guide_or<>0:
guide_m="No horizon defined!" + "\n" + "\n" + "Apparently you intended to define the horizon by a horizontal guide (ruler) but the guide that was found is vertical." + "\n" + "Take care to have just one horizontal guide and run the script again! (Shortcut: Ctrl+F)"
guide_mode=2
else:
guide_y=pdb.gimp_image_get_guide_position(img,guide_num_1)
guide_mode=1
guide_num = pdb.gimp_image_find_next_guide(img, guide_num_1)
if guide_num<>0:
guide_m="Horizon not clearly defined!" + "\n" + "\n" + "You decided to define the horizon by a guide (ruler) but more than one guide was found." + "\n" + "Take car to have just one guide and run the script again! (Shortcut: Ctrl+F)"
guide_y=0
guide_mode=2
return guide_mode, guide_y, guide_m
## MAKE "LIGHTNESS FILTER"
def make_lfilter(img,drw,softness,filter,f_colour):
blurr=int(img.width/5.0)+softness
gnd_mask = pdb.gimp_layer_create_mask(drw, 5)
pdb.gimp_layer_add_mask(drw,gnd_mask)
drw=gnd_mask
pdb.gimp_invert(drw)
pdb.gimp_levels(drw,0,0,128,0.1+softness/100.0*9.9,0,255)
pdb.plug_in_gauss(img,drw,blurr,blurr,0)
if filter>0:
add_colour(img,gnd_mask,f_colour)
## MAKE GRADIENT
def make_gradient(img,drw,horizon,softness,orientation,filter,f_colour):
h=img.height
gimp.set_foreground(255,255,255)
gimp.set_background(0,0,0)
x1=0
x2=0
y1=horizon
if orientation=="standard":
hplain=int(horizon-softness/100.0*horizon)
y2=hplain
else:
hplain=h-int((h-horizon)-(100-softness)/100.0*(h-horizon))
y2=y1+h-hplain
mask = pdb.gimp_layer_create_mask(drw, ADD_WHITE_MASK)
pdb.gimp_layer_add_mask(drw,mask)
drw=mask
pdb.gimp_edit_blend(drw, FG_BG_RGB_MODE, NORMAL_MODE, GRADIENT_LINEAR, 100, 0, REPEAT_NONE, False, False, 0, 0, True, x1, y1, x2, y2)
if filter>0:
add_colour(img,mask,f_colour)
## ADD COLOUR LAYER + LAYER MASK
def add_colour(img,mask,f_colour):
pdb.gimp_edit_copy(mask)
layer_colour = gimp.Layer(img, "", img.width, img.height, RGB_IMAGE, 50, OVERLAY_MODE)
img.add_layer(layer_colour, 0)
pdb.gimp_edit_paste(layer_colour, 0)
pdb.gimp_floating_sel_anchor(img.layers[0])
drw=layer_colour
pdb.gimp_invert(drw)
col_mask = pdb.gimp_layer_create_mask(drw, 5)
pdb.gimp_layer_add_mask(drw,col_mask)
gimp.set_foreground(f_colour)
drw=layer_colour
pdb.gimp_edit_bucket_fill(drw, 0, 0, 100, 255, False, 0, 0)
register(
"GRADUATED-FILTERS",
"Digitally create a Graduated Filter / Lightness Mask\n -- product of forum.meetthegimp.org --\n\nGiven two layers, simulate a horizontal Graduated Filter.\n\nThe horizon to be used for the start of the filter can be specified by a guide line; if not specified, it will be determined by this plug-in.\n\nThere is also a lightness mode which creates a layer mask based upon pixel lightness.\n\n",
"Graduated Filters",
"Berthold Hinz",
"public domain",
"2009",
"/Filters/Photo/Graduated Filters",
"RGB*, GRAY*",
[(PF_OPTION, "filter", ("Filter"), 0,["Neutral (GND)","Custom colour","Aqua","Blue","Chocolate","Fuchsia","Green","Lime","Maroon","Mauve","Navy","Olive","Orange","Purple","Red","Steelblue","Sunset","Teal","Tobacco","Yellow"]),
(PF_COLOUR,"f_colour"," Custom colour selection ", (170,190,255)),
(PF_SLIDER,"softness","Softness of Filter/Mask (%)",100,(1,100,10)),
(PF_RADIO, "type", ("Pixel darkening depends on "), "horizon", (("Distance from horizon", "horizon"),("Lightness", "lightness"))),
(PF_RADIO,"orientation",("Orientation"+"\n"+"(ignored in Lightness mode) "),"standard",(("Standard (filtering top)", "standard"), ("Flipped (filtering bottom)", "flipped"))),
],
[],
GFilters)
main()