Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
scripts for comics trip
#1
Hi there,
I do comics trip as a hobby. Here are some of my works. I use gimp for text, editing, sometimes coloring or texturing. I will show in this thread the scripts I did to ease some tasks. Comments and advice are welcome

This first script is made to prepare a scanned drawing. automatize de-saturating, changing contrast and light, and separate the ink from the background, so I can add a color layer in between and paint.

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP plugin to separe the ink form the paper of a b&w scan
# (c) Jacques Duflos 2023
#
#   History:
#
#   v0.0: 2023-xx-xx: First published version

#   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 2 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import sys, os
from gimpfu import *
import gimpcolor
#print "**********preparer un scan***************"
debug= False

def trace(s):
   if debug:
       print "****"
       print s
       print "****"
       



def preparerUnScan(image):
    image.undo_group_start()
    trace("1")
    # récupérer l'image et le calque selectionné
    layer = pdb.gimp_image_get_active_layer(image)
    layer_name = pdb.gimp_item_get_name(layer)
    trace("2  "+ layer_name)
    #désaturer, pousser le contraste très haut et augmenter un peu la luminosité.
    # voir pour en faire des paramètres éventuellement.
    pdb.gimp_drawable_desaturate(layer, 0)
    trace("3")
    pdb.gimp_drawable_brightness_contrast(layer, -0.2, 0.8)
    #enregistrer les variables de contexte avant de les modifier
    opacity_old = pdb.gimp_context_get_opacity()
    foreground_old = pdb.gimp_context_get_foreground()
    paint_mode_old = pdb.gimp_context_get_paint_mode()
    #print foreground_old
    pdb.gimp_context_set_opacity(100)
    pdb.gimp_context_set_foreground(gimpcolor.RGB(1.0, 1.0, 1.0, 1.0))
    pdb.gimp_context_set_paint_mode(LAYER_MODE_COLOR_ERASE)
    
    
    #effacer l'arrière plan blanc
    pdb.gimp_layer_add_alpha(layer)
    pdb.gimp_drawable_edit_fill(layer, FILL_FOREGROUND)
    trace("fond effacé")
    
    #créer le fond blanc
    fond = pdb.gimp_layer_new(image, pdb.gimp_image_width(image), pdb.gimp_image_height(image), RGB_IMAGE , "fond", 100, LAYER_MODE_NORMAL)
    num_layers, layer_ids = pdb.gimp_image_get_layers(image)
    pdb.gimp_image_add_layer(image, fond, num_layers)
    pdb.gimp_context_set_paint_mode(LAYER_MODE_NORMAL )
    pdb.gimp_drawable_edit_fill(fond, FILL_FOREGROUND)
    
    #rétablir les variables
    pdb.gimp_context_set_opacity(opacity_old)
    pdb.gimp_context_set_foreground(foreground_old)
    pdb.gimp_context_set_paint_mode(paint_mode_old)
    trace("contexte rétabli")
    
    image.undo_group_end()
    

### Registrations
whoiam='\n'+os.path.abspath(sys.argv[0])

register(
   'preparer-un-scan',
   'Prépare un scan %s' % whoiam,
   'prépare un scan',
   'Jacques Duflos','Jacques Duflos','2023',
   'Prépare un scan...',
   '*',
   [
       (PF_IMAGE,  'image',            'Image', None)
   ],
   [],
   preparerUnScan,
   menu='<Image>/Layer'
)

main()


This second script is made to move all the text layers in a layer group named texts.

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP plugin to move every text layer in a text layer group
# (c) Jacques Duflos 2023
#
#   History:
#
#   v0.0: 2023-xx-xx: First published version

#   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 2 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import sys, os
from gimpfu import *
import gimpcolor
print "**********calques texte dans groupe***************"
debug= True

def trace(s):
   if debug:
       print "**** "
       print s
       print "**** "
       
def calquesTextesDansGroupe(image):
    image.undo_group_start()
    trace("1")
    groupe_textes = pdb.gimp_layer_group_new(image)
    pdb.gimp_item_set_name(groupe_textes, "textes")
    pdb.gimp_image_insert_layer(image, groupe_textes, None, 0)
    calques=[]
    for numero_calque in range(pdb.gimp_image_get_layers(image)[0]):
        calques.append(image.layers[numero_calque])
    
    trace(calques)
    for calque in calques :
        if pdb.gimp_item_is_text_layer(calque):
            pdb.gimp_image_reorder_item(image, calque, groupe_textes, 0)
    
    image.undo_group_end()
    

### Registrations
whoiam='\n'+os.path.abspath(sys.argv[0])

register(
   'textes-dans-groupe',
   'Mettre les calques textes dans un groupe %s' % whoiam,
   'Mettre les calques textes dans un groupe',
   'Jacques Duflos','Jacques Duflos','2023',
   'Mettre les calques textes dans un groupe...',
   '*',
   [
       (PF_IMAGE,  'image',            'Image', None)
   ],
   [],
   calquesTextesDansGroupe,
   menu='<Image>/Layer'
)

main()

Im presently working on a script that makes a text bubble around a text layer.
enjoy !
Reply
#2
In the first script, instead of saving/restoring individual context settings, you should just bracket your code with gimp.context_push()/gimp.context_pop() (usually goes hand in hand with the undo_group calls).
Reply
#3
This next script exports as png all .xcf files of the same folder as the current image in a /rendu/ folder. I use it to export all the pages of the comics Im working on. I made it with chatgpt, it's the first time I use it to program, and I'm impressed.
Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP plugin to export all .xcf files of the folder in a /rendu/ folder
# (c) Jacques Duflos 2023
#
#   History:
#
#   v0.0: 2023-xx-xx: First published version

#   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 2 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import random
import sys, os
from gimpfu import *
import gimpcolor


debug = False
def trace(s):
   if debug:
       print "**** "
       print s
       print "**** "
trace("export group test")

def export_groupe(image):
   # Chemin complet vers le fichier actif
   chemin_fichier = image.filename

   # Obtenir le chemin du dossier contenant le fichier
   dossier = os.path.dirname(chemin_fichier)

   # Chemin du dossier de rendu
   dossier_rendu = os.path.join(dossier, 'Rendu')
   try:
       os.makedirs(dossier_rendu)
   except OSError:
       pass

   # Obtenir la liste des fichiers dans le même dossier
   fichiers_dossier = os.listdir(dossier)

   # Filtrer les fichiers avec l'extension ".xcf"
   fichiers_xcf = [fichier for fichier in fichiers_dossier if fichier.endswith(".xcf")]

   # Exporter les fichiers .xcf vers le dossier de rendu
   for fichier in fichiers_xcf:
       chemin_complet = os.path.join(dossier, fichier)
       nom_fichier, _ = os.path.splitext(fichier)

       # Charger le fichier .xcf dans GIMP
       image_xcf = pdb.gimp_xcf_load(0, chemin_complet, chemin_complet)

       # Exporter le fichier dans le dossier de rendu
       chemin_rendu = os.path.join(dossier_rendu, nom_fichier + ".png")
       new_image = pdb.gimp_image_duplicate(image_xcf)
       layer = pdb.gimp_image_merge_visible_layers(new_image, CLIP_TO_IMAGE)
       pdb.gimp_file_save(new_image, layer, chemin_rendu, '?')
       pdb.gimp_image_delete(new_image)
       pdb.gimp_image_delete(image_xcf)

    
    
### Registrations
whoiam='\n'+os.path.abspath(sys.argv[0])

register(
   'export-groupe',
   'exporter tous les .xcf du dossier %s' % whoiam,
   'exporter tous les .xcf du dossier',
   'Jacques Duflos','Jacques Duflos','2023',
   'exporter tous les .xcf du dossier...',
   '*',
   [
       (PF_IMAGE,  'image',            'Image', None),
   ],
   [],
   export_groupe,
   menu='<Image>/Layer'
)

main()
Reply
#4
(06-10-2023, 12:38 AM)jacques_duflos Wrote: I made it with chatgpt, it's the first time I use it to program, and I'm impressed.

Me, somewhat less so... looks like the intern's code  Rolleyes
  • glob.glob() does the filtering and returns the list of files with full paths: for instance glob.glob('Screenshots/*.png') returns ['Screenshots/OldStyle.png', 'Screenshots/MapObjectPlaneAxis.png'] and this would avoid some file name tinkering
  • duplicating the image is somewhat wasteful, saving the result of a layer-new-from-visible is sufficient: pdb.gimp_file_save(image,  pdb.gimp_layer_new_from_visible(image, image, "## saved"), '/tmp/foo.png','/tmp/foo.png')
  • catching an exception to bury it with a pass is heinous. Good luck if you can't create the directory.
Reply
#5
(06-10-2023, 07:23 AM)Ofnuts Wrote:
(06-10-2023, 12:38 AM)jacques_duflos Wrote: I made it with chatgpt, it's the first time I use it to program, and I'm impressed.

Me, somewhat less so... looks like the intern's code  Rolleyes
glade to hear that IAs are not ready to replace us all just yet Big Grin. I'm particularly impressed by the generation of a functional code that actually does what I asked in a human non-precise way.
About your observations :
  • glob.glob : I didn't know about this module. Is it "just" to gain one code line ? I can replace the two lines
    Code:
    fichiers_dossier = os.listdir(dossier)
     fichiers_xcf = [fichier for fichier in fichiers_dossier if fichier.endswith(".xcf")]
  • by the one line
    Code:
    fichiers_xcf = glob.glob(os.path.join(dossier, '*.xcf'))



  • duplicating the image : chatgpt originally just omitted the layer argument of the save function. I googled the problem and found a thread on stack overflow that claimed that the duplicate technique was the easiest and not-so-resource-consuming solution. But I'll take your advice, thanks.
  • skipping the directory creation : it was to avoid the error generation if the directory already exist. Chatgpt first proposed this line :
    os.makedirs(dossier_rendu, exist_ok=True)but it didn't work, because of the python version used by gimp I think (?). would the code
    Code:
    if not os.path.exists(dossier_rendu):os.makedirs(dossier_rendu)
    be more correct in your opinion ?

now my code looks like that

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# GIMP plugin to export all .xcf files of the folder in a /rendu/ folder
# (c) Jacques Duflos 2023
#
#   History:
#
#   v0.0: 2023-xx-xx: First published version

#   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 2 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.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import random
import sys, os
from glob import glob
from gimpfu import *
import gimpcolor


debug = False
def trace(s):
    if debug:
        print "**** "
        print s
        print "**** "
trace("export group test")

def export_groupe(image):
    # Chemin complet vers le fichier actif
    chemin_fichier = image.filename

    # Obtenir le chemin du dossier contenant le fichier
    dossier = os.path.dirname(chemin_fichier)

    # Chemin du dossier de rendu
    dossier_rendu = os.path.join(dossier, 'Rendu')

    # Check if the render directory already exists
    if not os.path.exists(dossier_rendu):os.makedirs(dossier_rendu)

    # Obtenir la liste des fichiers xcf dans le même dossier
    fichiers_xcf = glob(os.path.join(dossier, '*.xcf'))
    trace(fichiers_xcf)
    # Exporter les fichiers .xcf vers le dossier de rendu
    for fichier in fichiers_xcf:
        nom_fichier = os.path.basename(fichier)
        trace(nom_fichier)
        nom_fichier, _ = os.path.splitext(nom_fichier)
        trace(nom_fichier)
        # Charger le fichier .xcf dans GIMP
        image_xcf = pdb.gimp_xcf_load(0, fichier, fichier)

        # Exporter le fichier dans le dossier de rendu
        trace(dossier_rendu)
        trace(nom_fichier)
        chemin_rendu = os.path.join(dossier_rendu, nom_fichier + ".png")
        #trace(chemin_rendu)
        pdb.gimp_file_save(image_xcf,  pdb.gimp_layer_new_from_visible(image_xcf, image_xcf, "## saved"), chemin_rendu,chemin_rendu)
        pdb.gimp_image_delete(image_xcf)

    
    
### Registrations
whoiam='\n'+os.path.abspath(sys.argv[0])

register(
    'export-groupe',
    'exporter tous les .xcf du dossier %s' % whoiam,
    'exporter tous les .xcf du dossier',
    'Jacques Duflos','Jacques Duflos','2023',
    'exporter tous les .xcf du dossier...',
    '*',
    [
        (PF_IMAGE,  'image',            'Image', None),
    ],
    [],
    export_groupe,
    menu='<Image>/Layer'
)

main()
Reply
#6
  • glob.glob:  a bit more than this. What it returns is a list of files with paths. So you also avoir the reconstruction of the path+file later on.
  • directory: if not os.path.isdir(directory): mkdir(directory) so you avoid the error if the directory exists, and get a real error otherwise (access rights,  name is used by a file, etc...). You don't need makedirS since the parent already exist.
Reply


Forum Jump: