#!/usr/bin/env python3 import gi gi.require_version('Gimp', '3.0') from gi.repository import Gimp from gi.repository import GLib from gi.repository import GObject gi.require_version('Gtk', '3.0') from gi.repository import Gtk import sys from datetime import date plug_in_proc = 'plug-in-rgz-watermarkfu' plug_in_binary = 'rgz-watermarkfu' class WatermarkFu(Gimp.PlugIn): def do_query_procedures(self): return [ plug_in_proc ] def do_create_procedure(self, name): if name != plug_in_proc: return None procedure = Gimp.ImageProcedure.new(self, name, Gimp.PDBProcType.PLUGIN, self.run, None) procedure.set_sensitivity_mask (Gimp.ProcedureSensitivityMask.DRAWABLE | Gimp.ProcedureSensitivityMask.DRAWABLES) procedure.set_menu_label('WatermarkFu...') procedure.add_menu_path('/Filters/Render') procedure.set_attribution('Robert Günzler', 'rgz', '2023') procedure.set_documentation('Watermark your pictures', 'Watermark your pictures', name) procedure.add_string_argument('watermark', 'Watermark', None, 'My watermark', GObject.ParamFlags.READWRITE) procedure.add_string_argument('anotherline', 'Another line', None, '', GObject.ParamFlags.READWRITE) procedure.add_font_argument('font', 'Font', None, False, None, True, GObject.ParamFlags.READWRITE) procedure.add_double_argument('scalefactor_text', 'Scale Text', None, 0.0, 100.0, 0.2, GObject.ParamFlags.READWRITE) procedure.add_double_argument('scalefactor_boundary', 'Scale Boundary', None, 0.0, 100.0, 2.0, GObject.ParamFlags.READWRITE) procedure.add_double_argument('watermark_opacity', 'Opacity', None, 0.0, 100.0, 16.0, GObject.ParamFlags.READWRITE) return procedure def run(self, procedure, run_mode, img, drawables, config, data): if len(drawables) != 1: error = GLib.Error.new_literal( Gimp.PlugIn.error_quark(), f"Procedure '{procedure.get_name()}' only works with one drawable.", 0) return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR, error) if run_mode == Gimp.RunMode.INTERACTIVE: gi.require_version('GimpUi', '3.0') from gi.repository import GimpUi GimpUi.init(plug_in_binary) dialog = GimpUi.ProcedureDialog.new(procedure, config, 'WatermarkFu') box = dialog.fill_box('size-box', ['font-size', 'font-unit']) box.set_orientation (Gtk.Orientation.HORIZONTAL) dialog.fill_frame('size-frame', 'compute-size', True, 'size-box') dialog.fill([ 'watermark', 'anotherline', 'font', 'scalefactor_text', 'scalefactor_boundary', 'watermark_opacity' ]) if not dialog.run(): dialog.destroy() return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, None) else: dialog.destroy() # make copy of input img.undo_group_start() self.watermarkfu(img, drawables[0], watermark=config.get_property('watermark'), anotherline=config.get_property('anotherline'), font=config.get_property('font'), scalefactor_text=config.get_property('scalefactor_text'), scalefactor_boundary=config.get_property('scalefactor_boundary'), watermark_opacity=config.get_property('watermark_opacity')) img.undo_group_end() # try: # except: # img.undo_group_end() # return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR , None) return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, None) def watermarkfu(self, img, drawable, watermark, anotherline='', font=None, scalefactor_text=0.2, scalefactor_boundary=2.0, watermark_opacity=16.66): # simplify source image img.flatten() # expand text macro anotherline = anotherline.replace('', date.today().strftime('%Y-%m-%d')) # create text txt = Gimp.TextLayer.new(image=img, text=("\n".join([watermark, anotherline])), font=font, size=68, unit=Gimp.Unit.point()) # add to image, justification doesn't work otherwise img.insert_layer(txt, drawable.get_parent(), 0) # justify text txt.set_justification(Gimp.TextJustification.CENTER) img_width = img.get_width() img_height = img.get_height() layer_width = txt.get_width() layer_height = txt.get_height() # scale down text layer, maintaining ratio txt.scale(new_width=((float(layer_width)/layer_height)*(img_height*scalefactor_text)), new_height=(img_height*scalefactor_text), local_origin=True) # crate padding around text Gimp.Layer.resize(txt, new_width=(layer_width*scalefactor_boundary), new_height=(layer_height*scalefactor_boundary), offx=(((layer_width*scalefactor_boundary)-layer_width)/2), offy=(((layer_height*scalefactor_boundary)-layer_height)/2)) txt.set_offsets(offx=0, offy=0) pdb = Gimp.get_pdb() fu_tile = pdb.lookup_procedure('plug-in-tile') fu_tile_cfg = fu_tile.create_config() fu_tile_cfg.set_property('run-mode', Gimp.RunMode.NONINTERACTIVE) fu_tile_cfg.set_property('image', img) fu_tile_cfg.set_core_object_array('drawables', [txt]) fu_tile_cfg.set_property('new-width', img_width) fu_tile_cfg.set_property('new-height', img_height) fu_tile_cfg.set_property('new-image', False) fu_tile.run(fu_tile_cfg) layer = fu_tile.find_return_value('new-layer') print('???', layer) return # create watermark layer layer = Gimp.Layer.new(image=img, name='watermark', width=img_width, height=img_height, type=Gimp.ImageType.RGBA_IMAGE) # copy txt and make it the active pattern Gimp.Selection.all(img) Gimp.edit_copy([txt]) Gimp.context_set_pattern(Gimp.Pattern.get_by_name('Clipboard Image')) # do a pattern fill layer.fill(Gimp.FillType.PATTERN) # make transparent layer.set_mode(Gimp.LayerMode.HARDLIGHT) layer.set_opacity(watermark_opacity) img.insert_layer(layer, drawable.get_parent(), 0) # remove the txt layer img.remove_layer(txt) Gimp.main(WatermarkFu.__gtype__, sys.argv)