2024-11-08 21:07:34 +01:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
2025-06-22 16:21:18 +02:00
# (C) 2024-2026 ---
2025-02-03 17:42:38 +01:00
# 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 <https://www.gnu.org/licenses/>.
2024-11-08 21:07:34 +01:00
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
2025-05-25 21:14:16 +02:00
from pathlib import Path
2025-05-28 20:35:12 +02:00
from typing import Any , Callable , List , Optional , Tuple , Union
2024-11-08 21:07:34 +01:00
import os , sys , string , tempfile , platform
2024-11-09 15:55:37 +01:00
import subprocess
2024-11-08 21:07:34 +01:00
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 " )
2025-05-28 20:35:12 +02:00
REMBG_BASE_PATH = " "
def find_rembg_install ( ) - > Optional [ Path ] :
home = sys . exec_prefix
possible_paths = [ ]
# Common installation paths
if sys . platform == " win32 " :
possible_paths = [
2025-05-28 21:08:46 +02:00
Path ( " C:/Program Files (x86)/Rembg/ " ) ,
Path ( " C:/Program Files/Rembg/ " ) ,
2025-05-28 20:35:12 +02:00
]
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
2025-06-03 13:17:01 +02:00
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 )
2025-06-03 13:26:21 +02:00
dialog . set_title ( f " REMBG " )
2025-06-03 13:17:01 +02:00
dialog . run ( )
dialog . destroy ( )
2024-11-08 21:07:34 +01:00
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 )
2025-05-28 19:38:16 +02:00
procedure . set_menu_label ( _ ( " RemoveBG " ) )
2025-06-22 16:21:18 +02:00
procedure . set_attribution ( " M " ,
2024-11-08 21:07:34 +01:00
" (c) GPL V3.0 or later " ,
2025-03-12 16:11:27 +01:00
" 2024-2025 " )
2024-11-08 21:07:34 +01:00
procedure . add_menu_path ( ' <Image>/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 )
2025-04-15 14:24:15 +02:00
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 " , " " )
2024-11-08 21:07:34 +01:00
procedure . add_choice_argument ( " Model " , _ ( " Model " ) ,
2025-05-25 20:51:18 +02:00
_ ( " Model " ) , model_choice ,
2024-11-08 21:07:34 +01:00
" 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 ' )
2024-11-09 15:55:37 +01:00
selModel = config . get_choice_id ( " Model " )
aeValue = config . get_property ( ' aeValue ' )
2024-11-08 21:07:34 +01:00
removeTmpFile = True
tdir = tempfile . gettempdir ( )
print ( tdir )
2024-11-09 15:55:37 +01:00
jpgFileF = " Temp-gimp-0000.jpg "
jpgFile = os . path . join ( tdir , jpgFileF )
pngFileF = " Temp-gimp-0000.png "
pngFile = os . path . join ( tdir , pngFileF )
2024-11-08 21:07:34 +01:00
x1 = 0
y1 = 0
2024-11-09 15:55:37 +01:00
2024-11-08 21:07:34 +01:00
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 )
2025-05-28 20:35:12 +02:00
# aiExe = Path("C://Program Files (x86)/Rembg/rembg.exe")
aiExe = str ( find_rembg_install ( ) )
aiExe + = " /rembg.exe "
2024-11-09 15:55:37 +01:00
2024-11-08 21:07:34 +01:00
if AlphaMatting :
option = " -a -ae %d " % ( aeValue )
2024-11-09 15:55:37 +01:00
cmd = ' %s i -m %s %s " %s " " %s " ' % ( aiExe , tupleModel [ selModel ] , option , f . get_path ( ) , pngFile )
print ( cmd )
subprocess . run ( cmd )
2024-11-08 21:07:34 +01:00
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 :
2024-11-08 21:31:18 +01:00
image . select_item ( Gimp . ChannelOps . REPLACE , newlayer )
2025-05-25 21:50:49 +02:00
copyLayer = newlayer . copy ( )
2024-11-08 21:07:34 +01:00
image . remove_layer ( newlayer )
2024-11-08 21:31:18 +01:00
image . insert_layer ( copyLayer , None , - 1 )
2025-05-25 21:50:49 +02:00
mask = copyLayer . create_mask ( Gimp . AddMaskType . SELECTION )
2024-11-08 21:07:34 +01:00
copyLayer . add_mask ( mask )
2025-05-25 21:50:49 +02:00
image . get_selection ( ) . none ( image )
2024-11-08 21:07:34 +01:00
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 )