
What a large volume of adventures may be grasped within the span of his little life by him who interests his heart in everything.
~ Laurence Sterne.
Hi guys, one night I decided to create an online store and sell some drop ship products. The plan sounded simple: grab some pictures from the wholesale seller, customize them with a bit of store branding, and put them up for sale. The part I did not plan for was the volume.
There were a hundred images that I wanted to customize. By hand it would take ages, so I decided to create a batch script. My first thought was to use Gimp (an open source image manipulator) and Script-Fu, its native scripting language. After trying out what the result would be on the Python-Fu console, I settled with Python instead. It was a simple design, but I was satisfied, and more importantly, it was repeatable.
Here is the script that I use. Try it out on the Python-Fu console and call it convert_to_poster(n), where n is the image number in the image list inside Gimp. You could for loop it for faster batch processing.
๐งช The Script, Step by Step
First we set the variables. We grab the current image from Gimpโs image list, compute its center, and decide on a fixed canvas size of 600 by 600 pixels. The c_size_d is simply half of that size, which we will use to center the canvas crop:
current_image = gimp.image_list()[n]
center_x = current_image.width / 2
center_y = current_image.height / 2
c_size = 600
c_size_d = c_size / 2
Then we resize the image and canvas. This squeezes whatever dimensions the source photo had into our uniform 600 by 600 square, using the offsets to keep the original centered:
pdb.gimp_image_resize(current_image, c_size, c_size, c_size_d - center_x, c_size_d - center_y)
We create an empty background layer and just fill it with white. Every poster needs a solid base, and white keeps the branding readable:
bg_layer = pdb.gimp_layer_new(current_image, c_size, c_size, RGBA_IMAGE, "bg", 100, LAYER_MODE_NORMAL)
pdb.gimp_drawable_fill(bg_layer, FILL_WHITE)
pdb.gimp_image_add_layer(current_image, bg_layer, 1)
We will also set the main background and foreground color that would be used in future instruction sets. Indigo foreground, black background, these two colors are the whole brand palette:
pdb.gimp_context_set_foreground("#960acc")
pdb.gimp_context_set_background("#000000")
Create a branding layer and fill the rectangular region with indigo. This draws the colored band at the top of the poster where the text will eventually live:
branding_layer = pdb.gimp_layer_new(current_image, c_size, c_size, RGBA_IMAGE, "branding", 100, LAYER_MODE_NORMAL)
pdb.gimp_image_add_layer(current_image, branding_layer, 1)
pdb.gimp_selection_none(current_image)
pdb.gimp_image_select_rectangle(current_image, CHANNEL_OP_ADD, 0, 0, c_size, 260)
pdb.gimp_drawable_edit_fill(branding_layer, FILL_FOREGROUND)
Get the poster image and resize its layer to fit the canvas. The add_alpha call makes sure the layer supports transparency before we stretch it:
poster_layer = current_image.layers[0]
pdb.gimp_layer_add_alpha(poster_layer)
pdb.gimp_layer_resize_to_image_size(poster_layer)
Select non-alpha on the poster layer and grow. Growing the selection by 3 pixels gives us a slight edge outside the photo, which makes the next step look deliberate instead of accidental:
pdb.gimp_image_select_item(current_image, CHANNEL_OP_REPLACE, poster_layer)
pdb.gimp_selection_grow(current_image, 3)
Create a mask and fill it with the background color that we set. This creates a subtle black outline around the photo, separating it from the white base:
mask = pdb.gimp_layer_create_mask(branding_layer, ADD_MASK_WHITE)
pdb.gimp_layer_add_mask(branding_layer, mask)
pdb.gimp_layer_set_edit_mask(branding_layer, 1)
pdb.gimp_drawable_edit_fill(mask, FILL_BACKGROUND)
Add a text node with the color set to white. The store name goes on the indigo band, and the font is one that ships with the system:
pdb.gimp_context_set_foreground("#ffffff")
text_layer = pdb.gimp_text_fontname(current_image, None, 10.0, 10.0, "Psyche Digital", 0, 1, 24.0, PIXELS, "SF Compact Display Heavy")
We select the main layer and add a legacy drop shadow. That soft shadow behind the photo is what makes the poster feel like it has depth instead of looking like a flat collage:
pdb.gimp_image_select_item(current_image, CHANNEL_OP_REPLACE, poster_layer)
pdb.script_fu_drop_shadow(current_image, poster_layer, 10.0, 10.0, 10.0, (0, 0, 0, 255), 80, 0)
๐ The Full Script
Here is the full script code, all the pieces we walked through as one function:
def convert_to_poster(n):
current_image = gimp.image_list()[n]
center_x = current_image.width / 2
center_y = current_image.height / 2
c_size = 600
c_size_d = c_size / 2
pdb.gimp_image_resize(current_image, c_size, c_size, c_size_d - center_x, c_size_d - center_y)
bg_layer = pdb.gimp_layer_new(current_image, c_size, c_size, RGBA_IMAGE, "bg", 100, LAYER_MODE_NORMAL)
pdb.gimp_drawable_fill(bg_layer, FILL_WHITE)
pdb.gimp_image_add_layer(current_image, bg_layer, 1)
pdb.gimp_context_set_foreground("#960acc")
pdb.gimp_context_set_background("#000000")
branding_layer = pdb.gimp_layer_new(current_image, c_size, c_size, RGBA_IMAGE, "branding", 100, LAYER_MODE_NORMAL)
pdb.gimp_image_add_layer(current_image, branding_layer, 1)
pdb.gimp_selection_none(current_image)
pdb.gimp_image_select_rectangle(current_image, CHANNEL_OP_ADD, 0, 0, c_size, 260)
pdb.gimp_drawable_edit_fill(branding_layer, FILL_FOREGROUND)
poster_layer = current_image.layers[0]
pdb.gimp_layer_add_alpha(poster_layer)
pdb.gimp_layer_resize_to_image_size(poster_layer)
pdb.gimp_image_select_item(current_image, CHANNEL_OP_REPLACE, poster_layer)
pdb.gimp_selection_grow(current_image, 3)
mask = pdb.gimp_layer_create_mask(branding_layer, ADD_MASK_WHITE)
pdb.gimp_layer_add_mask(branding_layer, mask)
pdb.gimp_layer_set_edit_mask(branding_layer, 1)
pdb.gimp_drawable_edit_fill(mask, FILL_BACKGROUND)
pdb.gimp_context_set_foreground("#ffffff")
text_layer = pdb.gimp_text_fontname(current_image, None, 10.0, 10.0, "Psyche Digital", 0, 1, 24.0, PIXELS, "SF Compact Display Heavy")
pdb.gimp_image_select_item(current_image, CHANNEL_OP_REPLACE, poster_layer)
pdb.script_fu_drop_shadow(current_image, poster_layer, 10.0, 10.0, 10.0, (0, 0, 0, 255), 80, 0)
Run this code in the Gimp console or in the Script-Fu console.
๐ง Final Thoughts
That night I learned the most valuable lesson in automation: the first hour you spend writing the script is an hour that repays itself a hundred times over. A hundred images, one loop, zero boredom. If you ever find yourself doing the same image edit more than three times, stop and write a script, future you will be grateful.
๐ฅฐ๐๐๐๐
Leave a like and subscribe for more hacks, tips, and tricks.