 |
| Script Coder |
 |
Joined: May 07, 2014 Posts: 4469 Location: Canada
|
Something that spawned I think from Custom Shaped Looms and the make copies forgot the name. This plug-in will draw surrounders shapes/art around another shape using initial surrounder shape relative locations/rotation 1. On a separate layer with transparency, create a shape (of surroundee)  2. On another layer draw a surrounder (name it surrounder or something that you can remember, you'll have to choose this layer in later steps).  3. Run plug-in from menu (make sure you run it on the surroundEE layer and not the surroundER)  4. Select surrounder layer made in step 2. and set number of surrounders you want to populate  5. Plug-in will make copies of your surrounder layer and rotate it appropriately to surround your surroundee  Plug-in code below (save as .py file and put in your GIMP's /plug-ins/ folder found in Edit/Preferences/Folders/plug-ins) #!/usr/bin/env python # Author: (Tin Tran) # Created On: 2024.06.20 # License: Open source whatever the GIMP's license is. # Revisions: # 0.1 Initial Version
from gimpfu import * import math def slope_to_angle(slope): angle_radians = math.atan(slope) angle_degrees = math.degrees(angle_radians) return angle_degrees
def angle_from_points(x1, y1, x2, y2): # Calculate the difference in coordinates dx = x2 - x1 dy = y2 - y1 # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) return angle_degrees
def full_rotation_angle(dx, dy): # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) # Ensure the angle is positive and in the range [0, 360) if angle_degrees < 0: angle_degrees += 360 return angle_degrees
def surround_me(image,layer,surrounder,surrounders): pdb.gimp_image_select_item(image, CHANNEL_OP_REPLACE,layer)
#grab the vector after creation pdb.plug_in_sel2path(image,layer) active_vectors = pdb.gimp_image_get_active_vectors(image)
pdb.gimp_image_set_active_layer(image,surrounder) pdb.plug_in_autocrop_layer(image,surrounder) sx,sy = pdb.gimp_drawable_offsets(surrounder) cx,cy = sx+surrounder.width/2,sy+surrounder.height/2
num_strokes, stroke_ids = pdb.gimp_vectors_get_strokes(active_vectors) length = pdb.gimp_vectors_stroke_get_length(active_vectors,stroke_ids[0],0.1) minimum_dist = 1000000 surrounder_atlength = 0 for d in range(0,int(length-1)): pdb.gimp_progress_update(float(d)/length) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],d,0.1) away_dist = ((cx-x)**2+(cy-y)**2)**0.5 if (away_dist<minimum_dist): minimum_dist = away_dist surrounder_atlength = d #save this length
#here we should have a closest away dist stored in minimum_dist and surrounder_atlength pointing to that location x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],surrounder_atlength-0.1,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],surrounder_atlength,0.1) angle = full_rotation_angle(x-x1,y-y1)
angle_tosurrounder = angle_from_points(x,y,cx,cy)-angle #this will tell us how to rotate surrounder section = float(length)/surrounders for d in range(0,int(surrounders)): d = section*d+surrounder_atlength if (d>=length): #if it's longer then length then we subtract length like modding operation d = d-length if d > 0.1: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],d-0.1,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],d,0.1) else: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],d,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke_ids[0],d+0.1,0.1) anglenew = full_rotation_angle(x-x1,y-y1) angle_tosurrounder_inrad = math.radians(anglenew-angle+angle_tosurrounder) dx = x+math.cos(angle_tosurrounder_inrad)*minimum_dist dy = y+math.sin(angle_tosurrounder_inrad)*minimum_dist layer_copy = pdb.gimp_layer_new_from_drawable(surrounder,image) pdb.gimp_image_insert_layer(image,layer_copy,None,0) offx = dx-surrounder.width/2 offy = dy-surrounder.height/2 pdb.gimp_layer_set_offsets(layer_copy,offx,offy) pdb.gimp_item_transform_rotate(layer_copy,math.radians(anglenew-angle),TRUE,0,0) pdb.gimp_item_set_visible(surrounder,FALSE)
register( "python_fu_surround_me", "description", "longer description", "author name", "copyright name", "2024.06.20", "Surround Me...", "RGB*", # Alternately use RGB, RGB*, GRAY*, INDEXED etc. [ #INPUT BEGINS (PF_IMAGE, "image", "Image", None), (PF_DRAWABLE, "layer", "Drawable", None), (PF_DRAWABLE, "surrounder", "Surrounder:", None), (PF_INT, "surrounders", "# of Surrounders:", 18), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. #INPUT ENDS ], [], surround_me, menu="<Image>/Python-Fu")
main()
# Below is all the example input types for INPUTS for the plug-in which can be cut and pasted into #INPUT BEGINS section and edited to taste (found online years back that I didn't want to constantly look up) # Since GIMP is free anyways, I thought it would be handy here for me to CUT and PASTE, CHANGE, USE. # (PF_INT, "p0", "_INT:", 0), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. # (PF_FLOAT, "p02", "_FLOAT:", 3.141), # (PF_STRING, "p03", "_STRING:", "foo"), # alias PF_VALUE # (PF_TEXT, "p04", "TEXT:", "bar"), # # PF_VALUE # # Pick one from set of choices # (PF_OPTION,"p1", "OPTION:", 0, ["0th","1st","2nd"]), # initially 0th is choice # (PF_RADIO, "p16", "RADIO:", 0, (("0th", 1),("1st",0))), # note bool indicates initial setting of buttons # # PF_RADIO is usually called a radio button group. # # SLIDER, ADJUSTMENT types require the extra parameter of the form (min, max, step). # (PF_TOGGLE, "p2", "TOGGLE:", 1), # initially True, checked. Alias PF_BOOL # # PF_TOGGLE is usually called a checkbox. # (PF_SLIDER, "p3", "SLIDER:", 0, (0, 100, 10)), # (PF_SPINNER, "p4", "SPINNER:", 21, (1, 1000, 50)), # alias PF_ADJUSTMENT # # Pickers ie combo boxes ie choosers from lists of existing Gimp objects # (PF_COLOR, "p14", "_COLOR:", (100, 21, 40) ), # extra param is RGB triple # # PF_COLOUR is an alias by aussie PyGimp author lol # (PF_IMAGE, "p15", "IMAGE:", None), # should be type gimp.image, but None works # (PF_FONT, "p17", "FONT:", 0), # (PF_FILE, "p18", "FILE:", 0), # (PF_BRUSH, "p19", "BRUSH:", 0), # (PF_PATTERN, "p20", "PATTERN:", 0), # (PF_GRADIENT, "p21", "GRADIENT:", 0), # (PF_PALETTE, "p22", "PALETTE:", 0), # (PF_LAYER, "p23", "LAYER:", None), # (PF_CHANNEL, "p24", "CHANNEL:", None), # ??? Usually empty, I don't know why. # (PF_DRAWABLE, "p25", "DRAWABLE:", None), # # Mostly undocumented, but work # (PF_VECTORS, "p26", "VECTORS:", None), # (PF_FILENAME, "p27", "FILENAME:", 0), # (PF_DIRNAME, "p28", "DIRNAME:", 0) # # PF_REGION might work but probably of little use. See gimpfu.py.
version 0.2 handles shapes with holes #!/usr/bin/env python # Author: (Tin Tran) # Created On: 2024.06.20 # License: Open source whatever the GIMP's license is. # Revisions: # 0.1 Initial Version # 0.2 Handles multi-stroked shape (ie shape with hole(s))
from gimpfu import * import math def slope_to_angle(slope): angle_radians = math.atan(slope) angle_degrees = math.degrees(angle_radians) return angle_degrees
def angle_from_points(x1, y1, x2, y2): # Calculate the difference in coordinates dx = x2 - x1 dy = y2 - y1 # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) return angle_degrees
def full_rotation_angle(dx, dy): # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) # Ensure the angle is positive and in the range [0, 360) if angle_degrees < 0: angle_degrees += 360 return angle_degrees
def surround_me(image,layer,surrounder,surrounders): pdb.gimp_image_select_item(image, CHANNEL_OP_REPLACE,layer)
#grab the vector after creation pdb.plug_in_sel2path(image,layer) active_vectors = pdb.gimp_image_get_active_vectors(image)
pdb.gimp_image_set_active_layer(image,surrounder) pdb.plug_in_autocrop_layer(image,surrounder) sx,sy = pdb.gimp_drawable_offsets(surrounder) cx,cy = sx+surrounder.width/2,sy+surrounder.height/2
num_strokes, stroke_ids = pdb.gimp_vectors_get_strokes(active_vectors) minimum_dist = 1000000 surrounder_atlength = 0 surrounder_stroke = 0 length = 0.0 for stroke in stroke_ids: length += pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,0.1) for d in range(0,int(length-1)): pdb.gimp_progress_update(float(d)/length) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,0.1) away_dist = ((cx-x)**2+(cy-y)**2)**0.5 if (away_dist<minimum_dist): minimum_dist = away_dist surrounder_atlength = d #save this length surrounder_stroke = stroke
#here we should have a closest away dist stored in minimum_dist and surrounder_atlength pointing to that location x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength-0.1,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength,0.1) angle = full_rotation_angle(x-x1,y-y1)
angle_tosurrounder = angle_from_points(x,y,cx,cy)-angle #this will tell us how to rotate surrounder for stroke in stroke_ids: thislength = pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,0.1) section = float(length)/surrounders for d in range(0,int(float(thislength)/section)): d = section*d+surrounder_atlength while (d>=thislength): #if it's longer then length then we subtract length like modding operation d = d-thislength if d > 0.1: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d-0.1,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,0.1) else: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,0.1) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d+0.1,0.1) anglenew = full_rotation_angle(x-x1,y-y1) angle_tosurrounder_inrad = math.radians(anglenew-angle+angle_tosurrounder) dx = x+math.cos(angle_tosurrounder_inrad)*minimum_dist dy = y+math.sin(angle_tosurrounder_inrad)*minimum_dist layer_copy = pdb.gimp_layer_new_from_drawable(surrounder,image) pdb.gimp_image_insert_layer(image,layer_copy,None,0) offx = dx-surrounder.width/2 offy = dy-surrounder.height/2 pdb.gimp_layer_set_offsets(layer_copy,offx,offy) pdb.gimp_item_transform_rotate(layer_copy,math.radians(anglenew-angle),TRUE,0,0) pdb.gimp_item_set_visible(surrounder,FALSE)
register( "python_fu_surround_me", "description", "longer description", "author name", "copyright name", "2024.06.20", "Surround Me...", "RGB*", # Alternately use RGB, RGB*, GRAY*, INDEXED etc. [ #INPUT BEGINS (PF_IMAGE, "image", "Image", None), (PF_DRAWABLE, "layer", "Drawable", None), (PF_DRAWABLE, "surrounder", "Surrounder:", None), (PF_INT, "surrounders", "# of Surrounders:", 18), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. #INPUT ENDS ], [], surround_me, menu="<Image>/Python-Fu")
main()
# Below is all the example input types for INPUTS for the plug-in which can be cut and pasted into #INPUT BEGINS section and edited to taste (found online years back that I didn't want to constantly look up) # Since GIMP is free anyways, I thought it would be handy here for me to CUT and PASTE, CHANGE, USE. # (PF_INT, "p0", "_INT:", 0), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. # (PF_FLOAT, "p02", "_FLOAT:", 3.141), # (PF_STRING, "p03", "_STRING:", "foo"), # alias PF_VALUE # (PF_TEXT, "p04", "TEXT:", "bar"), # # PF_VALUE # # Pick one from set of choices # (PF_OPTION,"p1", "OPTION:", 0, ["0th","1st","2nd"]), # initially 0th is choice # (PF_RADIO, "p16", "RADIO:", 0, (("0th", 1),("1st",0))), # note bool indicates initial setting of buttons # # PF_RADIO is usually called a radio button group. # # SLIDER, ADJUSTMENT types require the extra parameter of the form (min, max, step). # (PF_TOGGLE, "p2", "TOGGLE:", 1), # initially True, checked. Alias PF_BOOL # # PF_TOGGLE is usually called a checkbox. # (PF_SLIDER, "p3", "SLIDER:", 0, (0, 100, 10)), # (PF_SPINNER, "p4", "SPINNER:", 21, (1, 1000, 50)), # alias PF_ADJUSTMENT # # Pickers ie combo boxes ie choosers from lists of existing Gimp objects # (PF_COLOR, "p14", "_COLOR:", (100, 21, 40) ), # extra param is RGB triple # # PF_COLOUR is an alias by aussie PyGimp author lol # (PF_IMAGE, "p15", "IMAGE:", None), # should be type gimp.image, but None works # (PF_FONT, "p17", "FONT:", 0), # (PF_FILE, "p18", "FILE:", 0), # (PF_BRUSH, "p19", "BRUSH:", 0), # (PF_PATTERN, "p20", "PATTERN:", 0), # (PF_GRADIENT, "p21", "GRADIENT:", 0), # (PF_PALETTE, "p22", "PALETTE:", 0), # (PF_LAYER, "p23", "LAYER:", None), # (PF_CHANNEL, "p24", "CHANNEL:", None), # ??? Usually empty, I don't know why. # (PF_DRAWABLE, "p25", "DRAWABLE:", None), # # Mostly undocumented, but work # (PF_VECTORS, "p26", "VECTORS:", None), # (PF_FILENAME, "p27", "FILENAME:", 0), # (PF_DIRNAME, "p28", "DIRNAME:", 0) # # PF_REGION might work but probably of little use. See gimpfu.py.
Don't update progress too often as it slows it down #!/usr/bin/env python # Author: (Tin Tran) # Created On: 2024.06.20 # License: Open source whatever the GIMP's license is. # Revisions: # 0.1 Initial Version # 0.2 Handles multi-stroked shape (ie shape with hole(s)) # 0.25 Don't update progress too often it slows it down from gimpfu import * import math import time def slope_to_angle(slope): angle_radians = math.atan(slope) angle_degrees = math.degrees(angle_radians) return angle_degrees
def angle_from_points(x1, y1, x2, y2): # Calculate the difference in coordinates dx = x2 - x1 dy = y2 - y1 # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) return angle_degrees
def full_rotation_angle(dx, dy): # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) # Ensure the angle is positive and in the range [0, 360) if angle_degrees < 0: angle_degrees += 360 return angle_degrees
def surround_me(image,layer,surrounder,surrounders): pdb.gimp_image_select_item(image, CHANNEL_OP_REPLACE,layer)
#grab the vector after creation pdb.plug_in_sel2path(image,layer) active_vectors = pdb.gimp_image_get_active_vectors(image)
pdb.gimp_image_set_active_layer(image,surrounder) pdb.plug_in_autocrop_layer(image,surrounder) sx,sy = pdb.gimp_drawable_offsets(surrounder) cx,cy = sx+surrounder.width/2,sy+surrounder.height/2
num_strokes, stroke_ids = pdb.gimp_vectors_get_strokes(active_vectors) minimum_dist = 1000000 surrounder_atlength = 0 surrounder_stroke = 0 length = 0.0 precision = 1.0 start = time.time() for stroke in stroke_ids: length += pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,precision) for d in range(0,int(length-1)): if (d%500==0): pdb.gimp_progress_update(float(d)/length) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,precision) away_dist = ((cx-x)**2+(cy-y)**2)**0.5 if (away_dist<minimum_dist): minimum_dist = away_dist surrounder_atlength = d #save this length surrounder_stroke = stroke pdb.gimp_message(time.time()-start) #here we should have a closest away dist stored in minimum_dist and surrounder_atlength pointing to that location x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength-0.1,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength,precision) angle = full_rotation_angle(x-x1,y-y1)
angle_tosurrounder = angle_from_points(x,y,cx,cy)-angle #this will tell us how to rotate surrounder for stroke in stroke_ids: thislength = pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,precision) section = float(length)/surrounders for d in range(0,int(float(thislength)/section)): d = section*d+surrounder_atlength while (d>=thislength): #if it's longer then length then we subtract length like modding operation d = d-thislength if d > 0.1: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d-0.1,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,precision) else: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d+0.1,precision) anglenew = full_rotation_angle(x-x1,y-y1) angle_tosurrounder_inrad = math.radians(anglenew-angle+angle_tosurrounder) dx = x+math.cos(angle_tosurrounder_inrad)*minimum_dist dy = y+math.sin(angle_tosurrounder_inrad)*minimum_dist layer_copy = pdb.gimp_layer_new_from_drawable(surrounder,image) pdb.gimp_image_insert_layer(image,layer_copy,None,0) offx = dx-surrounder.width/2 offy = dy-surrounder.height/2 pdb.gimp_layer_set_offsets(layer_copy,offx,offy) pdb.gimp_item_transform_rotate(layer_copy,math.radians(anglenew-angle),TRUE,0,0) pdb.gimp_item_set_visible(surrounder,FALSE)
register( "python_fu_surround_me", "description", "longer description", "author name", "copyright name", "2024.06.20", "Surround Me...", "RGB*", # Alternately use RGB, RGB*, GRAY*, INDEXED etc. [ #INPUT BEGINS (PF_IMAGE, "image", "Image", None), (PF_DRAWABLE, "layer", "Drawable", None), (PF_DRAWABLE, "surrounder", "Surrounder:", None), (PF_INT, "surrounders", "# of Surrounders:", 18), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. #INPUT ENDS ], [], surround_me, menu="<Image>/Python-Fu")
main()
# Below is all the example input types for INPUTS for the plug-in which can be cut and pasted into #INPUT BEGINS section and edited to taste (found online years back that I didn't want to constantly look up) # Since GIMP is free anyways, I thought it would be handy here for me to CUT and PASTE, CHANGE, USE. # (PF_INT, "p0", "_INT:", 0), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. # (PF_FLOAT, "p02", "_FLOAT:", 3.141), # (PF_STRING, "p03", "_STRING:", "foo"), # alias PF_VALUE # (PF_TEXT, "p04", "TEXT:", "bar"), # # PF_VALUE # # Pick one from set of choices # (PF_OPTION,"p1", "OPTION:", 0, ["0th","1st","2nd"]), # initially 0th is choice # (PF_RADIO, "p16", "RADIO:", 0, (("0th", 1),("1st",0))), # note bool indicates initial setting of buttons # # PF_RADIO is usually called a radio button group. # # SLIDER, ADJUSTMENT types require the extra parameter of the form (min, max, step). # (PF_TOGGLE, "p2", "TOGGLE:", 1), # initially True, checked. Alias PF_BOOL # # PF_TOGGLE is usually called a checkbox. # (PF_SLIDER, "p3", "SLIDER:", 0, (0, 100, 10)), # (PF_SPINNER, "p4", "SPINNER:", 21, (1, 1000, 50)), # alias PF_ADJUSTMENT # # Pickers ie combo boxes ie choosers from lists of existing Gimp objects # (PF_COLOR, "p14", "_COLOR:", (100, 21, 40) ), # extra param is RGB triple # # PF_COLOUR is an alias by aussie PyGimp author lol # (PF_IMAGE, "p15", "IMAGE:", None), # should be type gimp.image, but None works # (PF_FONT, "p17", "FONT:", 0), # (PF_FILE, "p18", "FILE:", 0), # (PF_BRUSH, "p19", "BRUSH:", 0), # (PF_PATTERN, "p20", "PATTERN:", 0), # (PF_GRADIENT, "p21", "GRADIENT:", 0), # (PF_PALETTE, "p22", "PALETTE:", 0), # (PF_LAYER, "p23", "LAYER:", None), # (PF_CHANNEL, "p24", "CHANNEL:", None), # ??? Usually empty, I don't know why. # (PF_DRAWABLE, "p25", "DRAWABLE:", None), # # Mostly undocumented, but work # (PF_VECTORS, "p26", "VECTORS:", None), # (PF_FILENAME, "p27", "FILENAME:", 0), # (PF_DIRNAME, "p28", "DIRNAME:", 0) # # PF_REGION might work but probably of little use. See gimpfu.py.
v0.3 (Fixed bugs, I nearly went nuts) #!/usr/bin/env python # Author: (Tin Tran) # Created On: 2024.06.20 # License: Open source whatever the GIMP's license is. # Revisions: # 0.1 Initial Version # 0.2 Handles multi-stroked shape (ie shape with hole(s)) # 0.25 Had errors # 0.3 Errors fixed for multiple strokes in a possibly weird shape like with holes. from gimpfu import * import math def slope_to_angle(slope): angle_radians = math.atan(slope) angle_degrees = math.degrees(angle_radians) return angle_degrees
def angle_from_points(x1, y1, x2, y2): # Calculate the difference in coordinates dx = x2 - x1 dy = y2 - y1 # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) return angle_degrees
def full_rotation_angle(dx, dy): # Calculate the angle in radians angle_radians = math.atan2(dy, dx) # Convert the angle to degrees angle_degrees = math.degrees(angle_radians) # Ensure the angle is positive and in the range [0, 360) if angle_degrees < 0: angle_degrees += 360 return angle_degrees
def surround_me(image,layer,surrounder,surrounders): pdb.gimp_image_select_item(image, CHANNEL_OP_REPLACE,layer)
#grab the vector after creation pdb.plug_in_sel2path(image,layer) active_vectors = pdb.gimp_image_get_active_vectors(image) pdb.gimp_selection_none(image)
pdb.gimp_image_set_active_layer(image,surrounder) pdb.plug_in_autocrop_layer(image,surrounder) sx,sy = pdb.gimp_drawable_offsets(surrounder) cx,cy = sx+surrounder.width/2,sy+surrounder.height/2
num_strokes, stroke_ids = pdb.gimp_vectors_get_strokes(active_vectors) minimum_dist = 1000000 surrounder_atlength = 0 surrounder_stroke = 0 surrounder_tlength = 0 length = 0.0 precision = 0.1 tlength = 0.0 clength = 0.0 for stroke in stroke_ids: #total length of all strokes tlength += pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,precision) strokeindex = 0 for stroke in stroke_ids: length = pdb.gimp_vectors_stroke_get_length(active_vectors,stroke,precision) for d in range(0,int(length-1)): if (d%100==0): pdb.gimp_progress_update(float(d)/length) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,stroke,d,precision) away_dist = ((cx-x)**2+(cy-y)**2)**0.5 if (away_dist<minimum_dist): minimum_dist = away_dist surrounder_atlength = d #save this length of current stroke surrounder_tlength = d+clength surrounder_stroke = stroke #marks which stroke the surrounder is on surrounder_strokeindex = strokeindex strokeindex += 1 clength += length #here we should have a closest away dist stored in minimum_dist and surrounder_atlength pointing to that location x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength-0.1,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,surrounder_stroke,surrounder_atlength,precision) angle = full_rotation_angle(x-x1,y-y1) angle_tosurrounder = angle - angle_from_points(x,y,cx,cy) #this will tell us how to rotate surrounder
clength = 0.0 #crawl current length d = 0.0 dc = 0.0 section = float(tlength)/surrounders #total length is used to find section cstrokeindex = surrounder_strokeindex cstroke = stroke_ids[cstrokeindex] cdist = surrounder_atlength dc = cdist running = True created = 0; while (running): thislength = pdb.gimp_vectors_stroke_get_length(active_vectors,cstroke,precision) while (True):
if (dc >= 0.1): x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,cstroke,dc-0.1,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,cstroke,dc,precision) else: x1,y1,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,cstroke,dc,precision) x,y,slope,valid = pdb.gimp_vectors_stroke_get_point_at_dist(active_vectors,cstroke,dc+0.1,precision) if valid==TRUE: anglenew = full_rotation_angle(x-x1,y-y1) angle_tosurrounder_inrad = math.radians(anglenew-angle_tosurrounder) dx = x+math.cos(angle_tosurrounder_inrad)*minimum_dist dy = y+math.sin(angle_tosurrounder_inrad)*minimum_dist layer_copy = pdb.gimp_layer_new_from_drawable(surrounder,image) pdb.gimp_image_insert_layer(image,layer_copy,None,0) offx = dx-surrounder.width/2 offy = dy-surrounder.height/2 pdb.gimp_layer_set_offsets(layer_copy,offx,offy) floating = pdb.gimp_item_transform_rotate(layer_copy,math.radians(anglenew-angle),TRUE,0,0) #exit condition when we reach number of surrounders because #I suck at logics and it's driving me nuts ============= created += 1; if (created == surrounders): running = False break; #======================================================= dc += section if dc >= thislength: break;
clength += thislength #updates current length to reflect that this past stroke was added dc = dc - thislength cstrokeindex = (cstrokeindex+1)%len(stroke_ids) #move to next stroke cstroke = stroke_ids[cstrokeindex]
pdb.gimp_item_set_visible(surrounder,FALSE)
register( "python_fu_surround_me", "description", "longer description", "author name", "copyright name", "2024.06.20", "Surround Me...", "RGB*", # Alternately use RGB, RGB*, GRAY*, INDEXED etc. [ #INPUT BEGINS (PF_IMAGE, "image", "Image", None), (PF_DRAWABLE, "layer", "Drawable", None), (PF_DRAWABLE, "surrounder", "Surrounder:", None), (PF_INT, "surrounders", "# of Surrounders:", 18), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. #INPUT ENDS ], [], surround_me, menu="<Image>/Python-Fu")
main()
# Below is all the example input types for INPUTS for the plug-in which can be cut and pasted into #INPUT BEGINS section and edited to taste (found online years back that I didn't want to constantly look up) # Since GIMP is free anyways, I thought it would be handy here for me to CUT and PASTE, CHANGE, USE. # (PF_INT, "p0", "_INT:", 0), # PF_INT8, PF_INT16, PF_INT32 similar but no difference in Python. # (PF_FLOAT, "p02", "_FLOAT:", 3.141), # (PF_STRING, "p03", "_STRING:", "foo"), # alias PF_VALUE # (PF_TEXT, "p04", "TEXT:", "bar"), # # PF_VALUE # # Pick one from set of choices # (PF_OPTION,"p1", "OPTION:", 0, ["0th","1st","2nd"]), # initially 0th is choice # (PF_RADIO, "p16", "RADIO:", 0, (("0th", 1),("1st",0))), # note bool indicates initial setting of buttons # # PF_RADIO is usually called a radio button group. # # SLIDER, ADJUSTMENT types require the extra parameter of the form (min, max, step). # (PF_TOGGLE, "p2", "TOGGLE:", 1), # initially True, checked. Alias PF_BOOL # # PF_TOGGLE is usually called a checkbox. # (PF_SLIDER, "p3", "SLIDER:", 0, (0, 100, 10)), # (PF_SPINNER, "p4", "SPINNER:", 21, (1, 1000, 50)), # alias PF_ADJUSTMENT # # Pickers ie combo boxes ie choosers from lists of existing Gimp objects # (PF_COLOR, "p14", "_COLOR:", (100, 21, 40) ), # extra param is RGB triple # # PF_COLOUR is an alias by aussie PyGimp author lol # (PF_IMAGE, "p15", "IMAGE:", None), # should be type gimp.image, but None works # (PF_FONT, "p17", "FONT:", 0), # (PF_FILE, "p18", "FILE:", 0), # (PF_BRUSH, "p19", "BRUSH:", 0), # (PF_PATTERN, "p20", "PATTERN:", 0), # (PF_GRADIENT, "p21", "GRADIENT:", 0), # (PF_PALETTE, "p22", "PALETTE:", 0), # (PF_LAYER, "p23", "LAYER:", None), # (PF_CHANNEL, "p24", "CHANNEL:", None), # ??? Usually empty, I don't know why. # (PF_DRAWABLE, "p25", "DRAWABLE:", None), # # Mostly undocumented, but work # (PF_VECTORS, "p26", "VECTORS:", None), # (PF_FILENAME, "p27", "FILENAME:", 0), # (PF_DIRNAME, "p28", "DIRNAME:", 0) # # PF_REGION might work but probably of little use. See gimpfu.py.
_________________ TinT My GIMP 2.10 plug-in writer Fiverr Gig Plaid Community Forum
plaid-patterns.com
Last edited by trandoductin on Fri Jun 21, 2024 3:25 pm, edited 2 times in total.
|
|