I tried to map the pattern using Polar Coordinates and well it's not seamless so this version tries to be seamless as possible (expect for the possible 1 pixel stray artifact).
#!/usr/bin/env python
# text-pattern.py
# Created by TT
#
# License: GPLv3
# 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 3 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.
#
# To view a copy of the GNU General Public License
# visit: http://www.gnu.org/licenses/gpl.html
#
#
# ------------
#| Change Log |
# ------------
# Rel 1: Initial release
# Rel 2: Adjust pattern so that it's repeated more often to look nicer.
# Rel 3: Added ability to choose number of random colors
# Rel 4: Added various random sizes for kicks
# Rel 5: Bug fix so that there's no white line showing between copies of pattern.
# Rel 6: Default to "Clip board" pattern so user doesn't have to select it and allow user to choose the font
# Rel 7: 50% of the time move the copy down, 50% move the original down to get upside down variations.
# Rel 8: Toggle to color the white background layer randomly as well
# Rel 9: Just default as the whole alphabet, and let user override with less letters
# Rel 10: Add variations with other side rotations
# Rel 11: Make pattern as close to seamless as possible when image is 2000x2000
from gimpfu import *
import random
colors = [["1","Blue Green","#199ebd"],
["2","Black","#232323"],
["3","Blue Violet","#7366bd"],
["4","Violet(Purple)","#926eae"],
["5","Green","#1cac78"],
["6","Blue","#1f75fe"],
["7","Yellow Green","#c5e384"],
["8","White","#ededed"],
["9","Yellow","#fce883"],
["10","Carnation Pink","#ffaacc"],
["11","Yellow Orange","#ffb653"],
["12","Red","#ee204d"],
["13","Brown","#b5674d"],
["14","Orange","#ff7538"],
["15","Red Orange","#ff5349"],
["16","Red Violet","#c0448f"],
["17","Gray","#95918c"],
["18","Cerulean","1dacd6"],
["19","Indigo","5d76cb"],
["20","Green Yellow","f0e891"],
["21","Dandelion","fddb6d"],
["22","Apricot","fdd9b5"],
["23","Violet Red","f75394"],
["24","Scarlet","fc2847"],
["25","Wisteria","#cda4de"],
["26","Sky Blue","#80daeb"],
["27","Cadet Blue","#b0b7c6"],
["28","Timberwolf","#dbd7d2"],
["29","Melon","#fdbcb4"],
["30","Peach","#ffcfab"],
["31","Tan","#faa76c"],
["32","Chestnut","#bc5d58"],
["33","Purple Mountains Majesty","#9d81ba"],
["34","Sea Green","#9fe2bf"],
["35","Cornflower","#9aceeb"],
["36","Granny Smith Apple","#a8e4a0"],
["37","Olive Green","#bab86c"],
["38","Spring Green","#eceabe"],
["39","Lavender","#fcb4d5"],
["40","Mauvelous","#ef98aa"],
["41","Goldenrod","#fcd975"],
["42","Salmon","#ff9baa"],
["43","Sepia","#a5694f"],
["44","Tumbleweed","#deaa88"],
["45","Macaroni and Cheese","#ffbd88"],
["46","Burnt Sienna","#ea7e5d"],
["47","Raw Sienna","#d68a59"],
["48","Mahogany","#cd4a4a"],
["49","Pacific Blue","#1ca9c9"],
["50","Robin Egg Blue","#1fcecb"],
["51","Turquoise","#77dde7"],
["52","Forest Green","#6dae81"],
["53","Silver","#cdc5c2"],
["54","Orchid","#c0448f"],
["55","Plum","#8e4584"],
["56","Periwinkle","#c5d0e6"],
["57","Asparagus","#87a96b"],
["58","Magenta","#f664af"],
["59","Tickle Me Pink","#fc89ac"],
["60","Wild Strawberry","#ff43a4"],
["61","Gold","#e7c697"],
["62","Bittersweet","#fd7c6e"],
["63","Burnt Orange","#ff7f49"],
["64","Brick Red","#cb4154"],
["65","Tropical Rain Forest","#17806d"],
["66","Pine Green","#158078"],
["67","Royal Purple","#7851a9"],
["68","Jungle Green","#3bb08f"],
["69","Denim","#2b6cc4"],
["70","Navy Blue","#1974d2"],
["71","Midnight Blue","#1a4876"],
["72","Shamrock","#45cea2"],
["73","Wild Blue Wonder","#a2add0"],
["74","Fuchsia","#c364c5"],
["75","Shocking Pink","#fb7efd"],
["76","Screamin Green","#76ff7a"],
["77","Inchworm","#b2ec5d"],
["78","Razzle Dazzle Rose","#ff48d0"],
["79","Hot Magenta","#ff1dce"],
["80","Purple Pizzazz","#ff1dce"],
["81","Electric Lime","#1df914"],
["82","Cerise","#ff43a4"],
["83","Laser Lemon","#fdfc74"],
["84","Unmellow Yellow","#fdfc74"],
["85","Razzmatazz","#e3256b"],
["86","Sunglow","#ffcf48"],
["87","Atomic Tangerine","#ffa474"],
["88","Vivid Tangerine","#ffa089"],
["89","Wild Watermelon","#fc6c85"],
["90","Jazzberry Jam","#ca3767"],
["91","Neon Carrot","#ffa343"],
["92","Mango Tango","#ff8243"],
["93","Radical Red","#ff496c"],
["94","Maroon","#c8385a"],
["95","Copper","#dd9475"],
["96","Outrageous Orange","#ff6e4a"],
["97","Outer Space","#414a4c"],
["98","Manatee","#979aaa"],
["99","Purple Heart","#7442c8"],
["100","Caribbean Green","#1cd3a2"],
["101","Eggplant","#6e5160"],
["102","Blue Bell","#adadd6"],
["103","Vivid Violet","#8f509d"],
["104","Mountain Meadow","#30ba8f"],
["105","Aquamarine","#78dbe2"],
["106","Pink Flamingo","#fc74fd"],
["107","Fern","#71bc78"],
["108","Canary","#ffff99"],
["109","Piggy Pink","#fdd7e4"],
["110","Shadow","#8a795d"],
["111","Banana Mania","#fae7b5"],
["112","Almond","#efdbc5"],
["113","Cotton Candy","#ffbcd9"],
["114","Blush","#de5d83"],
["115","Beaver","#9f8170"],
["116","Desert Sand","#efcdb8"],
["117","Pink Sherbet","#f780a1"],
["118","Antique Brass","#cd9575"],
["119","Sunset Orange","#fd5e53"],
["120","Fuzzy Wuzzy","#cc6666"],
];
def hexToRGB(h):
h = h.lstrip('#')
return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
def python_text_pattern(image, layer,fontname,string,cols,varysize,colorbackground):
pdb.gimp_image_undo_group_start(image)
pdb.gimp_context_push()
#YOUR CODE BEGINS=======================
words = string
starty = 0
count = 0;
random.shuffle(colors)
#set pattern to clip board (1st item)
num_patterns,pattern_list = pdb.gimp_patterns_get_list("")
pdb.gimp_context_set_pattern(pattern_list[0])
while starty < image.height:
#main work of each letter goes here ==========
#get random color
c = random.randrange(0,int(cols))
pdb.gimp_context_set_foreground(hexToRGB(colors[c][2]))
if (int(colorbackground)==1):
b = c;
while b==c:
b = random.randrange(0,int(cols))
text = words[random.randrange(len(words))]
text_layer = pdb.gimp_text_fontname(image,layer,0,0,text,0,TRUE,80*image.width/1200,0,fontname)
pdb.gimp_floating_sel_to_layer(text_layer)
pdb.gimp_image_raise_item_to_top(image,text_layer)
pdb.plug_in_autocrop_layer(image,text_layer)
if (int(varysize) == 1):
sizet = random.randrange(80,180) / 100.0
layer_copy = pdb.gimp_item_transform_scale(text_layer,0,0,text_layer.width*sizet,text_layer.height*sizet)
layer_copy = pdb.gimp_layer_new_from_drawable(text_layer,image)
pdb.gimp_image_insert_layer(image,layer_copy,None,0)
layer_copy = pdb.gimp_item_transform_flip_simple(layer_copy,ORIENTATION_VERTICAL,TRUE,0)
#50% of the time move the copy, the other 50% of the time move the original to get upside variations
if (random.randrange(0,100)<50):
layer_copy = pdb.gimp_item_transform_translate(layer_copy,0,layer_copy.height*2/3)
else:
text_layer = pdb.gimp_item_transform_translate(text_layer,0,text_layer.height*2/3)
layer_copy = pdb.gimp_image_merge_down(image,layer_copy,EXPAND_AS_NECESSARY)
pdb.gimp_layer_set_offsets(layer_copy,0,0)
height = layer_copy.height
pdb.gimp_image_select_rectangle(image,CHANNEL_OP_REPLACE,0,height*3/10.0,layer_copy.width,height*2/5.0)
pdb.gimp_selection_invert(image)
pdb.gimp_edit_clear(layer_copy)
pdb.gimp_selection_none(image)
pdb.plug_in_autocrop_layer(image,layer_copy)
#add variation with sideway rotations
if (random.randrange(0,100)<50):
pdb.gimp_item_transform_rotate_simple(layer_copy,ROTATE_90,TRUE,0,0)
else:
pdb.gimp_item_transform_rotate_simple(layer_copy,ROTATE_270,TRUE,0,0)
#vary up the size for kicks
pdb.gimp_layer_set_offsets(layer_copy,0,0)
pdb.gimp_image_select_rectangle(image,CHANNEL_OP_REPLACE,0,0,layer_copy.width,layer_copy.height)
pdb.gimp_edit_copy(layer_copy)
pdb.gimp_selection_none(image)
new_layer = pdb.gimp_layer_new(image,int(2000/layer_copy.width)*layer_copy.width-1,layer_copy.height,RGBA_IMAGE,"text pattern",100,LAYER_MODE_NORMAL)
pdb.gimp_image_insert_layer(image,new_layer,None,0)
pdb.gimp_edit_fill(new_layer,FILL_PATTERN)
pdb.gimp_item_transform_scale(new_layer,0,0,2000,layer_copy.height) #scale it down to 2000
pdb.gimp_layer_set_offsets(new_layer,0,starty)
#fill the layer with background color
if (int(colorbackground)==1):
pdb.gimp_context_set_foreground(hexToRGB(colors[b][2]))
pdb.gimp_image_select_rectangle(image,CHANNEL_OP_REPLACE,0,starty,image.width,new_layer.height)
pdb.gimp_edit_fill(layer,FILL_FOREGROUND)
starty += new_layer.height
pdb.gimp_image_remove_layer(image,layer_copy)
#YOUR CODE ENDS ========================
pdb.gimp_context_pop()
pdb.gimp_image_undo_group_end(image)
pdb.gimp_displays_flush()
#return
register(
"python_fu_text_pattern",
"Create Text Pattern",
"Create Text Pattern",
"TT",
"TT",
"March 8, 2023",
"<Image>/Python-Fu/Text Pattern...",
"*", # Create a new image, don't work on an existing one
[
#INPUT BEGINS
(PF_FONT, "fontname", "Font", 0),
(PF_STRING, "string", "Characters to use (randomly):", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), # alias PF_VALUE
(PF_SPINNER, "colors", "Number of Maximum Colors (randomly):", 16, (1, 32, 1)),
(PF_TOGGLE, "varysize", "Vary up sizes:", 1), # initially True, checked. Alias PF_BOOL
(PF_TOGGLE, "colorbackground", "Color background randomly:", 0), # initially True, checked. Alias PF_BOOL
#(PF_SPINNER, "inc", "Increments (pixels):", 15, (1, 1000, 1)),
#(PF_SPINNER, "outof", "Best out of:", 100, (1, 1000, 1)),
#(PF_OPTION, "arrow_side", "Arrows Ends:", SIDE_END, SIDE_NAMES),
#(PF_TOGGLE, "arrow_close", "Arrows Close:", 0),
#(PF_SPINNER, "ignorelayers", "Ignore first (no of layers):", 2, (0, 200, 1)),
#(PF_SPINNER, "shadow_offset_x", "Shadow Offset X:", 6, (-4096,4096,1)),
#(PF_SPINNER, "shadow_offset_y", "Shadow Offset Y:", 6, (-4096,4096,1)),
#(PF_SPINNER, "shadow_blur_radius", "Shadow Blur Radius:", 15, (0,1024,1)),
#(PF_SPINNER, "shadow_opacity", "Shadow Opacity:", 100, (0,100,1)),
#INPUT ENDS
],
[],
python_text_pattern)
main()
# (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.