Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
"Simple" python script in gimp 3
#5
Hi!
Sure:
Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import os
import gi
import random
gi.require_version('Gimp', '3.0')
from gi.repository import Gimp
gi.require_version('Gegl', '0.4')
from gi.repository import Gegl
from gi.repository import GLib
from gi.repository import Gio


def N_(message): return message
def _(message): return GLib.dgettext(None, message)

class TilesetVariants (Gimp.PlugIn):
   def do_query_procedures(self):
       return [ "plug-in-tileset-variants" ]

   def do_create_procedure(self, name):
       procedure = Gimp.ImageProcedure.new(self, name,
                                           Gimp.PDBProcType.PLUGIN,
                                           self.run, None)

       procedure.set_image_types("*")
       procedure.set_sensitivity_mask (Gimp.ProcedureSensitivityMask.DRAWABLE)

       procedure.set_menu_label(_("tileset"))
       procedure.add_menu_path('<Image>/Filters/Tileset/')

       procedure.set_documentation(_("Plug-in example in Python 3"),
                                   _("Plug-in example in Python 3"),
                                   name)
       procedure.set_attribution("ignis", "ignis", "2025")

       return procedure

   def run(self, procedure, run_mode, image, drawables, config, run_data):
       Gimp.message("running")
       try:
           tileset_variants(image,drawables)
       except Exception as e:
           Gimp.message(f"error: {e}")

       # do what you want to do, then, in case of success, return:
       return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())


#apply normal filter to the layer
def apply_normalMap(layer):
   filter = Gimp.DrawableFilter.new(layer, "gegl:normal-map", "Normal Map")
   filter.set_blend_mode(Gimp.LayerMode.REPLACE)
   filter.set_opacity(1.0)
   config = filter.get_config()
   config.set_property('scale', 100)
   filter.update()
   layer.append_filter(filter)    

#apply hsv noise to the filter
def apply_noise(layer):
   filter = Gimp.DrawableFilter.new(layer, "gegl:noise-hsv", "Add HSV Noise")
   filter.set_blend_mode(Gimp.LayerMode.REPLACE)
   filter.set_opacity(1.0)
   #config = filter.get_config()
   #config.set_property('Dulling', 2)
   #config.set_property('Hue', 3)
   #config.set_property('Saturation', 0.04)
   #config.set_property('Value', 0.04)

   filter.update()
   layer.append_filter(filter)    

#create a layer, and fill up with grayscale noise between min and max value
def generate_noise(image,min,max,w,h):
   layers = []
   for i in range(4):
       layer = Gimp.Layer.new(image, "Noise_" + str(i), w, h,
                      Gimp.ImageType.RGBA_IMAGE, 100.0, Gimp.LayerMode.NORMAL)
       image.insert_layer(layer, None, -1)

       color_format = "#{:02x}{:02x}{:02x}"
       colors = []
       for c in range(min,max+1):
           colors.append(Gegl.Color.new(color_format.format(c,c,c)))
               
       for y in range(h):
           for x in range(w):
               cp = random.randint(0,len(colors)-1)
               #pixels.extend([gray, gray, gray, 255])  # R, G, B, A
               layer.set_pixel(x,y,colors[cp])
     
       layer.merge_shadow(True)
       layer.update(0, 0, w, h)

       layer.set_offsets(i * w, 0)
       layer.set_mode(Gimp.LayerMode.OVERLAY)
       layer.set_visible(False)

       layers.append(layer)
   return layers

#rename the layer: workaround: remove layer, copy layer, rename new layer, add to image the new layer
def rename_layer(image,layer,name):
   if not layer:
       return None
   parent = layer.get_parent()
   position = image.get_item_position(layer)
   image.remove_layer(layer)
   new_layer = layer.copy()
   new_layer.set_name(name)
   image.insert_layer(new_layer, parent, position)
   return new_layer

#create rotated images and offset is
def generate_variants(image,layer,width):
   if layer == None:
       return [None]*4
   variants = [layer]
   for angle in range(1,4):
       rotated = layer.copy()
       rotated.set_name(layer.get_name()+"_"+str(angle))
       image.insert_layer(rotated, None, -1)
       rotate_angle = Gimp.RotationType.DEGREES90
       if angle == 2:
           rotate_angle =Gimp.RotationType.DEGREES180
       if angle == 3:
           rotate_angle =Gimp.RotationType.DEGREES270
       rotated.transform_rotate_simple(rotate_angle,True,0,0)
       floating=image.get_selected_layers()
       # many times get an error, cant anchor not floating image
       # if I leave it, one or two image not moved and/or not rotated
       try:
           Gimp.floating_sel_anchor(floating[0])
       except Exception as e:
           pass
       rotated.set_offsets(angle * width, 0)
       variants.append(rotated)

   return variants

# get the mask layer, select the black color, and fill the selection with neutral gray on the noise layer
def mask_noise(componed_layers,image):
   Gimp.context_set_background(Gegl.Color.new("#808080"))

   for i in range(4):
       mask = componed_layers["Mask"][i]
       if mask!=None:
           image.select_color(Gimp.ChannelOps.REPLACE, mask, Gegl.Color.new("#000000"))
           noise_layer = componed_layers["Noise"][i]
           image.active_layer =  noise_layer
           noise_layer.edit_fill(Gimp.FillType.BACKGROUND)
           # to be sure noting is selected
           selection = image.get_selection()
           selection.none(image)

# get the noise layer, the normal layer, and the noise addon, and merged together
def merge_noise(componed_layers,image):
   #merge noise es tarsai:
   for i in range(4):
       noise = componed_layers["Noise"][i]
       normal = componed_layers["Normal"][i]
       addon = componed_layers["Addon"][i]
       noise.set_visible(True)
       normal.set_visible(True)
       image.reorder_item(normal,None,-1)
       image.reorder_item(noise, None,-1)
       name = normal.get_name()
       Gimp.message(normal.get_name())
       if addon!=None:
           addon.set_visible(True)
           image.reorder_item(addon, None,-1)
       image.active_layer =  normal
       normal = image.merge_visible_layers(Gimp.MergeType.EXPAND_AS_NECESSARY)
       #need to rename the last layer
       Gimp.message(normal.get_name())
       normal=rename_layer(image,normal,name)
       componed_layers["Normal"][i]=normal
       normal.set_visible(False)

# generate noise for the Color image
# get the mask, select the black, invert the selection, and generate the noise into the selection on the color layer
def color_noise(componed_layers,image):

   for i in range(4):
       color = componed_layers["Color"][i]
       mask = componed_layers["ColorMask"][i]
       color.set_visible(True)
       image.reorder_item(color,None,-1)
       apply = color
       if mask!=None:
           mask.set_visible(True)
           image.reorder_item(mask, None,-1)
           image.select_color(Gimp.ChannelOps.REPLACE, mask, Gegl.Color.new("#000000"))
           selection = image.get_selection()
           selection.invert(image)
           apply = selection
       image.active_layer =  color
       
       apply_noise(apply)
       selection = image.get_selection()
       if selection:
           selection.none(image)
       color.set_visible(False)

# main function
def tileset_variants(image, drawable):
   Gimp.message("variant running")
   # get the file name to the export
   orig_path = image.get_file().get_path()
   basename = os.path.basename(orig_path)
   dirname = os.path.dirname(orig_path)
   new_name = os.path.splitext(basename)[0] + ".ora"
   output_path = os.path.join(dirname, new_name)
   Gimp.message("before")

   image.undo_group_start()

   #set up dedicated layers
   color = None
   heightmap = None
   mask = None
   normal = None
   addon = None
   colormask = None

   #Extract layers
   for layer in image.get_layers():
       layer.set_visible(False)
       # Color: visible texture
       if layer.get_name() == "Color":
           color = layer
       # Heightmap    
       if layer.get_name() == "Heightmap":
           heightmap = layer
       # Mask, where dont need noise for heightmap
       if layer.get_name() == "Noisemask":    
           mask = layer
       # layer added to the heightmap aka details
       if layer.get_name() == "Heightaddon":    
           addon = layer
       # color mask, where deont need noise for color layer
       if layer.get_name() == "Colormask":    
           colormask = layer


   width = image.get_width()
   height = image.get_height()

   # resize image
   image.resize(width * 4, height,0,0)

   # duplicate heightmap, rename to normal
   normal = heightmap.copy()
   normal.set_name("Normal")
   image.insert_layer(normal, None, -1)

   #collect the layers
   all_layers = {"Color":color, "Heightmap":heightmap, "Normal":normal,"Mask":mask,"Addon":addon,"ColorMask":colormask}

   # rotate and shift, create dict for layers
   componed_layers={}
   for name,layer in all_layers.items():
       variants = generate_variants(image,layer,width)
       componed_layers[name]=variants
   
   # generate noise layer
   componed_layers["Noise"]=generate_noise(image,123,133,width,height)

   # create noise
   mask_noise(componed_layers,image)

   #create heightmap for normal (apply noise, mask, details onto the copied heightmap)
   merge_noise(componed_layers,image)

   #apply normal map filter
   for i in range(4):
       normal = componed_layers["Normal"][i]
       apply_normalMap(normal)

   #apply color noise
   color_noise(componed_layers,image)

   #merge down each group
   Gimp.message("flattening")
   for name,layer in componed_layers.items():
       Gimp.message("group: "+name)
       needMerge = False
       for l in layer:
           if l:
               Gimp.message("layer: "+l.get_name())
               l.set_visible(True)
               image.active_layer =  l
               needMerge = True
       if needMerge:
           merged = image.merge_visible_layers(Gimp.MergeType.EXPAND_AS_NECESSARY)
           if merged:
               Gimp.message("rename: "+merged.get_name())
               merged=rename_layer(image,merged,name)      
               merged.set_visible(False)
               image.active_layer =  merged

   #try to export as openraster
   Gimp.file_save(Gimp.RunMode.INTERACTIVE,image, Gio.File.new_for_path(output_path),None)
   
   image.undo_group_end()    
   Gimp.message("End")


Gimp.main(TilesetVariants.__gtype__, sys.argv)
I tried to put a lots of comment

Thanx
Csaba
Reply


Messages In This Thread
RE: "Simple" python script in gimp 3 - by IgnisVeneficus - 07-30-2025, 07:14 PM

Forum Jump: