Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
GIMP Plugin for automating the boilerplate involved in colorizing manga pages my way
#!/usr/bin/python
"""Simple GIMP helper to automate the boierplate of my approach to colorizing
manga pages.
Usage:
1. Run this plugin from "Image > Start Colorizing..."
2. Select the regions to be colored using whatever approach you find works
best. This script will preserve the original image as the bottom layer
(hidden below a solid white layer) so it can easily be used as input for
selection methods which don't play nicely with transparency.
3. Switch to the "Colors" layer and bucket-fill your selections.
4. Use a similar process with pure white, targeting the "Fluids" layer,
to fill in translucent droplets like water or sweat.
5. If any characters have blush lines, unlock the "Lines" and "Blush Lines"
layers and cut-and-paste the lines from one to the other.
6. If the style calls for a "glow" to the blush, select the blush lines
feather the selection by 10 or 20 pixels, and then bucket fill the color
from the "Blush Lines Color" layer into the selection on the
"Blush Glow" layer.
Reference materials used:
- https://www.ibm.com/developerworks/library/os-autogimp/
- https://www.gimp.org/docs/python/
- http://zwell.net/content/pygimp.html
- https://www.gimp-forum.net/Thread-Debugging-python-fu-scripts-in-Windows
- https://stackoverflow.com/q/10221926/435253
"""
__author__ = "Stephan Sokolow (deitarion/SSokolow)"
__license__ = "GNU GPL 2.0 or later"
from contextlib import contextmanager
# pylint: disable=import-error
from gimpfu import gimp, main, pdb, register
from gimpfu import NORMAL_MODE, RGBA_IMAGE, SCREEN_MODE
from gimpfu import FOREGROUND_FILL, WHITE_FILL
@contextmanager
def undo_group(image):
"""Simple context manager to reliably undo-group a set of operations."""
pdb.gimp_image_undo_group_start(image)
try:
yield
finally:
pdb.gimp_image_undo_group_end(image)
class Image(object): # pylint: disable=too-few-public-methods
"""Transient helper to perform a bunch of operations on the same image"""
def __init__(self, image):
self.image = image
self.w = pdb.gimp_image_width(image)
self.h = pdb.gimp_image_height(image)
# pylint: disable=too-many-arguments
def add_layer(self, name, fill=None, opacity=100, mode=NORMAL_MODE,
parent=None, copy_from=None):
"""Deduplicating wrapper for adding layers"""
if copy_from is not None:
layer = pdb.gimp_layer_copy(copy_from, 0)
pdb.gimp_item_set_name(layer, name)
else:
layer = pdb.gimp_layer_new(self.image,
self.image.width, self.image.height,
RGBA_IMAGE, name, opacity, mode)
if fill is not None:
if isinstance(fill, int):
pdb.gimp_drawable_fill(layer, fill)
else:
orig_fg = pdb.gimp_context_get_foreground()
try:
pdb.gimp_context_set_foreground((255, 0, 0))
pdb.gimp_drawable_fill(layer, FOREGROUND_FILL)
finally:
pdb.gimp_context_set_foreground(orig_fg)
pdb.gimp_item_set_lock_content(layer, True)
pdb.gimp_image_insert_layer(self.image, layer, parent, 0)
return layer
def plugin_main(timg, tdrawable):
"""Expand a single layer into the colorization template I use"""
# Ensure that the image is in RGB mode to save a manual step
if not pdb.gimp_drawable_is_rgb(tdrawable):
pdb.gimp_image_convert_rgb(timg)
img = Image(timg)
# Get the bottom layer's ID
lyr_orig_image = gimp.Item.from_id(pdb.gimp_image_get_layers(timg)[-1][-1])
pdb.gimp_item_set_lock_content(lyr_orig_image, True)
# Insert a white layer above it
img.add_layer("White Background", fill=WHITE_FILL)
# Insert a layer for colors above that
lyr_colors = img.add_layer("Colors")
pdb.gimp_item_set_lock_content(lyr_colors, False)
# Insert a half-opacity for fluids above that
img.add_layer("Fluids", opacity=50)
# Insert a Color-to-Alpha'd copy of the line art above that
lyr_lines = img.add_layer("Lines", copy_from=lyr_orig_image)
pdb.gimp_item_set_lock_content(lyr_lines, False)
pdb.plug_in_colortoalpha(timg, lyr_lines, (255, 255, 255))
pdb.gimp_item_set_lock_content(lyr_lines, True)
# Insert layer group for drawing blushes
lyr_grp_blush = pdb.gimp_layer_group_new(timg)
pdb.gimp_item_set_name(lyr_grp_blush, "Blush")
pdb.gimp_image_insert_layer(timg, lyr_grp_blush, None, 0)
img.add_layer("Blush Lines", parent=lyr_grp_blush)
img.add_layer("Blush Lines Color", parent=lyr_grp_blush,
mode=SCREEN_MODE, fill=(255, 0, 0))
img.add_layer("Blush Glow", parent=lyr_grp_blush, opacity=50)
# NOTE: All layers except "colors" start locked to avoid accidents but
# "Fluids", "Blush Lines", and "Blush Glow" are intended to be
# added to.
#
# Likewise, it's important to not modify "Lines" under normal
# circumstances, but it's necessary when moving portions of its
# content to the "Blush Lines" layer.
# Focus the original image's layer, because I like to start by using
# the magic wand select tool.
pdb.gimp_image_set_active_layer(timg, lyr_orig_image)
desc = ("Helper to automate the boierplate of my approach to colorizing manga"
" pages")
author = "Stephan Sokolow"
register(
"manga_coloring_helper",
desc, desc,
author, author, "2019",
"<Image>/Image/Start Colorizing...",
"RGB*, GRAY*, INDEXED*",
[], [], plugin_main
)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.