Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Blending in Images into Mockups automatically
#1
Photo 
Hello Guys,

I am currently setting up an online shop where i have mockups of digital art.
I am relatively new to gimp but i am fairly trusted with scripting/coding.
I already managed to write a plugin which rescales a file to several formats.

Now i want to fit an image into the empty mockups. Since i dont want to waste hours doing that manually, i want to automate this.

Example:
1. I have my blank Mockup Image
2. I have my image which does not yet fit into the mockup space
3. Now i have to insert the image into the mockup image
4. Now i have to rescale and move the image to the mockup space and make it blend in perfectly
5. Save the mockup with the inserted image

I want to automate this procedure so i can chose a set of images and then they get inserted into different mockups automatically.
Is there any function/plugin like this?
If no is it possible to create a fu-python plugin myself to achieve this?
Basically the mockup does not change. The empty space will always have the same position and size. I just have to fit the image to it.

Thanks in advance if anyone can help me!

Best Regards
Daniel
Reply
#2
(03-28-2024, 11:55 AM)kaiserart Wrote: Is there any function/plugin like this?
If no is it possible to create a fu-python plugin myself to achieve this?
Basically the mockup does not change. The empty space will always have the same position and size. I just have to fit the image to it.
  • None I know of
  • Yes
  • You probably want to keep the mockup as an XCF mark the empty space with a layer at the right size/position
You can also do this with ImageMagick compose but you have to find an external way to remember the size/position of the empty space.
Reply
#3
(03-28-2024, 12:06 PM)Ofnuts Wrote:
(03-28-2024, 11:55 AM)kaiserart Wrote: Is there any function/plugin like this?
If no is it possible to create a fu-python plugin myself to achieve this?
Basically the mockup does not change. The empty space will always have the same position and size. I just have to fit the image to it.
  • None I know of
  • Yes
  • You probably want to keep the mockup as an XCF mark the empty space with a layer at the right size/position
You can also do this with ImageMagick compose but you have to find an external way to remember the size/position of the empty space.

Thanks for your reply. I managed to create a plugin for myself which iterates through every image in a folder and then through every mockup in a folder.
Then scales and positions the image according to the mockup and create a blurred shadow around it to make it more seamless.

Still i have one more question.
When the script finishes actually successfully it says in a GIMP Message:

"Unable to run GimpPdbProgress callback. The corresponding plug-in may have crashed."

Here is my Script (it is rather rudimental, also with absolute paths):

Code:
from gimpfu import *
import os

def set_stroke_params():
   # Set opacity to 100%
   pdb.gimp_context_set_opacity(100)

   # Set paint mode to NORMAL
   pdb.gimp_context_set_paint_mode(0)  # NORMAL mode

   # Set paint method to GRAYA (this is the default)
   pdb.gimp_context_set_paint_method("gimp-paintbrush")  # GRAYA method

   # Set stroke method to PAINT
   pdb.gimp_context_set_stroke_method("0")  # PAINT method

   # Set foreground color to black
   pdb.gimp_context_set_foreground((0, 0, 0))  # Black color

   # Set active brush (assuming you've already defined the brush)
   brush_name = "Circle (01)"
   pdb.gimp_context_set_brush(brush_name)

   # Set line width to 10
   pdb.gimp_context_set_line_width(6)

   # Enable antialiasing
   pdb.gimp_context_set_antialias(True)

def create_outline_layer(mockup_image, scaled_image):
   # Create a new layer filled with transparent color
   outline_layer = pdb.gimp_layer_new(mockup_image, scaled_image.width, scaled_image.height, RGBA_IMAGE, "Outline", 100, NORMAL_MODE)
   pdb.gimp_image_insert_layer(mockup_image, outline_layer, None, 0)

   return outline_layer

def mockup_scaleandmove_horizontal(image, drawable):
   mockups = ["WoodFrame_1.jpg", "BlackBorder_1.jpg", "Gaming_1.jpg", "Gaming_2.jpg", "LivingRoom_1.jpg"]
   pos_x = [295, 113, 212, 303, 163]
   pos_y = [611, 236, 112, 171, 115]
   scale_x = [1461, 801, 492, 436, 699]
   scale_y = [850, 540, 290, 270, 435]
   mockup_folder_path = "C:/Users/Daniel Kunz/Desktop/MidJourney/Mockups/Horizontal/Frontal"
   original_folder_path = "C:/Users/Daniel Kunz/Desktop/MidJourney/NewArt"
   mockup_image_path = ""
   original_image_path = ""
   
   # Iterate through each new file
   for filename_original in os.listdir(original_folder_path):
       # Check if it's a file
       if os.path.isfile(os.path.join(original_folder_path, filename_original)):
           original_image_path = original_folder_path + "/" + filename_original
           # Iterate through each mockup
           for index, mockup in enumerate(mockups):
               # Iterate through each file in the folder
               for filename_mockup in os.listdir(mockup_folder_path):
                   # Check if it's a file
                   if os.path.isfile(os.path.join(mockup_folder_path, filename_mockup)):
                       if filename_mockup == mockup:
                           # Set Mockup Image Path
                           mockup_image_path = mockup_folder_path + "/" + filename_mockup
                           # Load the Mockup Image
                           mockup_image = pdb.gimp_file_load(mockup_image_path, mockup_image_path)

                           # Load the Original Image
                           original_image = pdb.gimp_file_load(original_image_path, original_image_path)

                           # Resize the original image to fit the mockup
                           pdb.gimp_image_scale(original_image, scale_x[index], scale_y[index])

                           # Create a new layer in the mockup image
                           layer = pdb.gimp_layer_new_from_drawable(original_image.active_drawable, mockup_image)

                           # Add the layer to the mockup image
                           pdb.gimp_image_insert_layer(mockup_image, layer, None, 0)

                           # Move the layer to the fixed position
                           pdb.gimp_layer_translate(layer, pos_x[index], pos_y[index])
                           
                           # Create a new layer with only the outline of the selection
                           outline_layer = create_outline_layer(mockup_image, original_image)
                           # Move the layer to the fixed position
                           pdb.gimp_layer_translate(outline_layer, pos_x[index], pos_y[index])
                           # Select the outline
                           pdb.gimp_selection_all(outline_layer.image)
                           # Stroke the selection to draw a line around it
                           set_stroke_params()
                           pdb.gimp_drawable_edit_stroke_selection(outline_layer)
                           # Apply Gaussian blur to the outline layer
                           pdb.plug_in_gauss(mockup_image, outline_layer, 10, 10, 1)
                           # Merge the blurred stroke layer with the original layer
                           # Merge visible layers
                           merged_layer = pdb.gimp_image_merge_visible_layers(mockup_image, CLIP_TO_IMAGE)
                           #pdb.gimp_image_merge_down(mockup_image, outline_layer, EXPAND_AS_NECESSARY)

                           # Save the merged image
                           output_filename = filename_original[:-4] + filename_mockup + ".jpg"
                           output_foldername = "{}".format(filename_original[:-4])
                           output_folder = "C:/Users/Daniel Kunz/Desktop/MidJourney/Images/NewMockups/" + output_foldername
                           # Check if the directory already exists
                           if not os.path.exists(output_folder):
                               # If it doesn't exist, create the directory
                               os.makedirs(output_folder)
                           filename = os.path.join(output_folder, output_filename[:-4])
                           pdb.gimp_file_save(mockup_image, merged_layer, filename, filename)

                           # Close the images to conserve memory
                           pdb.gimp_image_delete(mockup_image)
                           pdb.gimp_image_delete(original_image)
           
   # Notify user
   gimp.message("Images rescaled, stroke painted, and saved successfully!")

register(
   "python_fu_mockup_scaleandmove_horizontal",
   "Rescale, paint stroke, and save images",
   "Rescale the input image into 5 different sizes, paint a stroke around the scaled and moved original image, and save them with DPI set to 300.",
   "Daniel Kunz",
   "Daniel Kunz",
   "2024",
   "<Image>/Filters/Mockup ScaleAndMove Horizontal",
   "",
   [],
   [],
   mockup_scaleandmove_horizontal)

main()
Reply
#4
No idea...

Otherwise very many oddities... how much of this comes from ChatGPT or equivalent?
Reply
#5
(03-28-2024, 09:14 PM)Ofnuts Wrote: No idea...

Otherwise very many oddities... how much of this comes from ChatGPT or equivalent?

I used it to get the right commands for the image transformations and the general usage for a gimp plugin, but noticed that it used some outdated ones. And also wrong sometimes so it was a lot of adjusting manually...
The rest i programmed myself.
Reply
#6
Then some suggestions:

Use the new form of registration (menu entry and menu location in distinct parameters) and avoid the useless image/drawable parameters

Code:
def mockup_scaleandmove_horizontal():  # No arguments until you add useful ones such as inpout/output directories
    # Current code goes here

register(
   "python_fu_mockup_scaleandmove_horizontal",
   "Rescale, paint stroke, and save images",
   "Rescale the input image into 5 different sizes, paint a stroke around the scaled and moved original image, and save them with DPI set to 300.",
   "Daniel Kunz",
   "Daniel Kunz",
   "2024",
   "Mockup ScaleAndMove Horizontal",
   "",
   [],
   [],
   mockup_scaleandmove_horizontal,
   menu="<Image>/Filters/")

Avoid the "parallel arrays" "anti-pattern", use an array of tuples:

Code:
   mockups = [
       ("WoodFrame_1.jpg",     295,  611,  1461, 850),
       ("BlackBorder_1.jpg",   113,  236,  801,  540),
       ("Gaming_1.jpg",        212,  112,  492,  290),
       ("Gaming_2.jpg",        303,  171,  436,  270),
       ("LivingRoom_1.jpg"     163,  115,  699,  435),
       ]

Then iterate and unpack the mockups:

Code:
for index, mockup in enumerate(mockups):
    pdb.gimp_image_scale(original_image, scale_x[index], scale_y[index])
    pdb.gimp_layer_translate(outline_layer, pos_x[index], pos_y[index])

becomes:

Code:
for mockup, pos_x, pos_y, scale_x, scale_y in mockups:
    pdb.gimp_image_scale(original_image, scale_x, scale_y)
    pdb.gimp_layer_translate(outline_layer, pos_x, pos_y)

Instead of loading two separate images, and copying a layer from the second to the first, you can use pdb.gimp_file_load_layer(image, filename) to load a file directly as a layer (that you still need to insert at the right position).

Since your code changes the context (the whole of set_stroke_params() (which in passing you can call only once outside of the loops)), you can bracket the whole script between pdb.gimp-context-push() and pdb.gimp-context-pop() calls to restore the initial context when done.

Use os.path.splitext() to extract the root name of a file, and os.path.join() to create a full path from directories and file names.

Code:
output_foldername = "{}".format(filename_original[:-4])
is definitely the weirdest line of code, because it is just a very complicated way to do
Code:
output_foldername = filename_original[:-4]
or more properly (see above):
Code:
output_foldername = os.path.splitext(filename_original)[0]
Reply
#7
(03-29-2024, 08:20 AM)Ofnuts Wrote: Then some suggestions:

Use the new form of registration (menu entry and menu location in distinct parameters) and avoid the useless image/drawable parameters

Code:
def mockup_scaleandmove_horizontal():  # No arguments until you add useful ones such as inpout/output directories
    # Current code goes here

register(
   "python_fu_mockup_scaleandmove_horizontal",
   "Rescale, paint stroke, and save images",
   "Rescale the input image into 5 different sizes, paint a stroke around the scaled and moved original image, and save them with DPI set to 300.",
   "Daniel Kunz",
   "Daniel Kunz",
   "2024",
   "Mockup ScaleAndMove Horizontal",
   "",
   [],
   [],
   mockup_scaleandmove_horizontal,
   menu="<Image>/Filters/")

Avoid the "parallel arrays" "anti-pattern", use an array of tuples:

Code:
   mockups = [
       ("WoodFrame_1.jpg",     295,  611,  1461, 850),
       ("BlackBorder_1.jpg",   113,  236,  801,  540),
       ("Gaming_1.jpg",        212,  112,  492,  290),
       ("Gaming_2.jpg",        303,  171,  436,  270),
       ("LivingRoom_1.jpg"     163,  115,  699,  435),
       ]

Then iterate and unpack the mockups:

Code:
for index, mockup in enumerate(mockups):
    pdb.gimp_image_scale(original_image, scale_x[index], scale_y[index])
    pdb.gimp_layer_translate(outline_layer, pos_x[index], pos_y[index])

becomes:

Code:
for mockup, pos_x, pos_y, scale_x, scale_y in mockups:
    pdb.gimp_image_scale(original_image, scale_x, scale_y)
    pdb.gimp_layer_translate(outline_layer, pos_x, pos_y)

Instead of loading two separate images, and copying a layer from the second to the first, you can use pdb.gimp_file_load_layer(image, filename) to load a file directly as a layer (that you still need to insert at the right position).

Since your code changes the context (the whole of set_stroke_params() (which in passing you can call only once outside of the loops)), you can bracket the whole script between pdb.gimp-context-push() and pdb.gimp-context-pop() calls to restore the initial context when done.

Use os.path.splitext() to extract the root name of a file, and os.path.join() to create a full path from directories and file names.

Code:
output_foldername = "{}".format(filename_original[:-4])
is definitely the weirdest line of code, because it is just a very complicated way to do
Code:
output_foldername = filename_original[:-4]
or more properly (see above):
Code:
output_foldername = os.path.splitext(filename_original)[0]

Thank you so much. This made the code so much clearer and made me understand the gimp scripting better!
It works perfectly...
Reply


Forum Jump: