#!/usr/bin/env python3 # -*- coding: utf-8 -*- # (C) 2024-2026 --- # This file is part of gimp-python-fu-removebg . # gimp-python-fu-removebg 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 2 of the License, or (at your option) any later version. # gimp-python-fu-removebg 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 Xfce-nameday-plugin. If not, see . import gi gi.require_version('Gimp', '3.0') from gi.repository import Gimp gi.require_version('GimpUi', '3.0') from gi.repository import GimpUi from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio gi.require_version('Gtk', '3.0') from gi.repository import Gtk from pathlib import Path from typing import Any, Callable, List, Optional, Tuple, Union import os, sys, string, tempfile, platform import subprocess def N_(message): return message def _(message): return GLib.dgettext(None, message) tupleModel = ("u2net","u2net_human_seg", "u2net_cloth_seg", "u2netp", "silueta", "isnet-general-use", "isnet-anime", "sam", "birefnet-general" ,"birefnet-general-lite", "birefnet-portrait", "birefnet-dis", "birefnet-hrsod", "birefnet-cod", "birefnet-massive" ) REMBG_BASE_PATH = "" def find_rembg_install() -> Optional[Path]: home = sys.exec_prefix possible_paths = [] # Common installation paths if sys.platform == "win32": possible_paths = [ Path("C:/Program Files (x86)/Rembg/"), Path("C:/Program Files/Rembg/"), ] for path in possible_paths: if path.is_dir(): return path # Fallback to user-configured path if specified if REMBG_BASE_PATH and (nik_path := Path(REMBG_BASE_PATH)).is_dir(): return nik_path show_alert( text="rembg installation path not found", message="Please specify the correct installation path 'REMBG_BASE_PATH' in the script.", ) return None def show_alert(text: str, message: str, parent=None) -> None: """Popup a message dialog with the given text and message""" dialog = Gtk.MessageDialog( transient_for=parent, flags=0, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE, text=text, ) dialog.format_secondary_text(message) dialog.set_title(f"REMBG") dialog.run() dialog.destroy() class PythonRemoveBG(Gimp.PlugIn): ## GimpPlugIn virtual methods ## def do_set_i18n(self, procname): return True, 'gimp30-python', None def do_query_procedures(self): return [ 'python-fu-removebg' ] def do_create_procedure(self, name): procedure = Gimp.ImageProcedure.new(self, name, Gimp.PDBProcType.PLUGIN, self.removebg, None) procedure.set_sensitivity_mask(Gimp.ProcedureSensitivityMask.ALWAYS) procedure.set_documentation (_("Remove Background AI"), _("Remove Background AI"), name) procedure.set_menu_label(_("RemoveBG")) procedure.set_attribution("M", "(c) GPL V3.0 or later", "2024-2025") procedure.add_menu_path('/Filters/RemoveBG/') procedure.add_boolean_argument("asMask","as Mask","As mask",False,GObject.ParamFlags.READWRITE) procedure.add_boolean_argument("AlphaMatting","AlphaMatting","AlphaMatting",False,GObject.ParamFlags.READWRITE) procedure.add_double_argument("aeValue","aeValue","aeValue",0,100,15 ,GObject.ParamFlags.READWRITE) model_choice = Gimp.Choice.new() model_choice.add("u2net",0,"u2net","") model_choice.add("u2net_human_seg",1,"u2net_human_seg","") model_choice.add("u2net_cloth_seg",2,"u2net_cloth_seg","") model_choice.add("u2netp",3,"u2netp","") model_choice.add("silueta",4,"silueta","") model_choice.add("isnet-general-use",5,"isnet-general-use","") model_choice.add("isnet-anime",6,"isnet-anime","") model_choice.add("sam",7,"sam","") model_choice.add("birefnet-general",8,"birefnet-general","") model_choice.add("birefnet-cod",9,"birefnet-cod","") model_choice.add("birefnet-massive",10,"birefnet-massive","") model_choice.add("birefnet-portrait",11,"birefnet-portrait","") model_choice.add("birefnet-general-lite",12,"birefnet-general-lite","") model_choice.add("birefnet-hrsod",13,"birefnet-hrsod","") model_choice.add("birefnet-dis",14,"birefnet-dis","") procedure.add_choice_argument ("Model", _("Model"), _("Model"), model_choice, "u2net", GObject.ParamFlags.READWRITE) return procedure def removebg(self, procedure, run_mode, image, drawables, config, run_data) : if run_mode == Gimp.RunMode.INTERACTIVE: GimpUi.init('python-fu-removebg.py') dialog = GimpUi.ProcedureDialog(procedure=procedure, config=config) dialog.fill(None) if not dialog.run(): dialog.destroy() return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error()) else: dialog.destroy() AlphaMatting = config.get_property('AlphaMatting') asMask = config.get_property('asMask') selModel = config.get_choice_id("Model") aeValue = config.get_property('aeValue') removeTmpFile = True tdir = tempfile.gettempdir() print(tdir) jpgFileF = "Temp-gimp-0000.jpg" jpgFile = os.path.join(tdir,jpgFileF) pngFileF = "Temp-gimp-0000.png" pngFile = os.path.join(tdir,pngFileF) x1 = 0 y1 = 0 option = "" Gimp.context_pop() image.undo_group_start() curLayer = image.get_selected_layers() fileOut = Gio.File.new_for_path(pngFile) file = Gio.File.new_for_path(jpgFile) f = image.get_file() if curLayer[0]: if not file.query_exists(): file.create(Gio.FileCreateFlags.REPLACE_DESTINATION , None) else: pdb.gimp_edit_copy(drawable) non_empty, x1, y1, x2, y2 = pdb.gimp_selection_bounds(image) tmpImage = gimp.Image(x2-x1, y2-y1, 0) tmpDrawable = gimp.Layer(tmpImage, "Temp", tmpImage.width, tmpImage.height, RGB_IMAGE, 100, NORMAL_MODE) pdb.gimp_image_add_layer(tmpImage, tmpDrawable, 0) pat = pdb.gimp_context_get_pattern() pdb.gimp_context_set_pattern("Leopard") pdb.gimp_drawable_fill(tmpDrawable, 4) pdb.gimp_context_set_pattern(pat) pdb.gimp_floating_sel_anchor(pdb.gimp_edit_paste(tmpDrawable,TRUE)) pdb.file_jpeg_save(tmpImage, tmpDrawable, jpgFile, jpgFile, 0.95, 0, 1, 0, "", 0, 1, 0, 0) pdb.gimp_image_delete(tmpImage) # aiExe = Path("C://Program Files (x86)/Rembg/rembg.exe") aiExe = str(find_rembg_install()) aiExe += "/rembg.exe" if AlphaMatting: option = "-a -ae %d" % (aeValue) cmd = '%s i -m %s %s "%s" "%s"' % (aiExe, tupleModel[selModel], option, f.get_path(), pngFile) print(cmd) subprocess.run(cmd) file_exists = os.path.exists(pngFile) if file_exists: newlayer = Gimp.file_load_layer(run_mode,image,fileOut) image.insert_layer(newlayer, None,-1) if asMask: image.select_item(Gimp.ChannelOps.REPLACE, newlayer) copyLayer = newlayer.copy() image.remove_layer(newlayer) image.insert_layer(copyLayer,None, -1) mask = copyLayer.create_mask(Gimp.AddMaskType.SELECTION) copyLayer.add_mask(mask) image.get_selection().none(image) image.undo_group_end() Gimp.displays_flush() if removeTmpFile: if file.query_exists(): file.delete() if fileOut.query_exists(): fileOut.delete() return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error()) Gimp.main(PythonRemoveBG.__gtype__, sys.argv)