0

From this question I have the following code:

def create_collage(cols, rows, width, height, listofimages):
    thumbnail_width = width//cols
    thumbnail_height = height//rows
    size = thumbnail_width, thumbnail_height
    new_im = Image.new('RGB', (width, height)) # 300 pt border
    ims = []
    for p in listofimages:
        im = Image.open(p)
        im.thumbnail(size)
        ims.append(im)
    i = 0
    x = 0
    y = 0
    for col in range(cols):
        for row in range(rows):
            new_im.paste(ims[i], (x, y))
            i += 1
            y += thumbnail_height
        x += thumbnail_width
        y = 0

    new_im.save("out.png", "PNG", quality=80, optimize=True, progressive=True)

But I need borders between images. I then found this answer here, so I adapted the code as follows:

def create_collage(images_per_row, img_width, img_height, padding, frame_width, images):
    sf = (frame_width - (images_per_row - 1) * padding) / (images_per_row * img_width) # scaling factor
    scaled_img_width = ceil(img_width * sf)
    scaled_img_height = ceil(img_height * sf) + padding # THIS NEEDED CHANGING as no horizontal borders were showing
    number_of_rows = ceil(len(images) / images_per_row)
    frame_height = ceil(sf * img_height * number_of_rows)
    
    new_im = Image.new('RGB', (frame_width, frame_height))
    
    i, j =0, 0
    for num, im in enumerate(images):
        if num % images_per_row == 0:
            i = 0
        im = Image.open(im)
        im.thumbnail((scaled_img_width, scaled_img_height))
        y_cord = (j // images_per_row) * scaled_img_height
        new_im.paste(im, (i, y_cord))
        i = (i + scaled_img_width) + padding
        j += 1

    new_im.save("out.png", "PNG", quality = 80, optimize = True, progressive = True)

Which is almost working, but now I am getting a border at the bottom of the image, which is not what I want.

How do I get consistent horizontal and vertical borders between images of a collage, without them appearing outside the collage?

Jake Ireland
  • 543
  • 4
  • 11

1 Answers1

0

Here's what I have now, with the help of a friend. I may accept this as the answer to my question, though I am hopeful someone else has a cleaner solution. This answer is based on the second code snippet above:

from PIL import Image
import glob
from math import ceil, floor

listofimages = glob.glob("directory/*") # this is where you need to put your path to directory

def create_collage(images_per_row, img_width, img_height, padding, images):
    frame_width = (width * images_per_row) + (padding * (images_per_row - 1))
    cell_width = ceil((frame_width + padding) / images_per_row)
    new_image_width = cell_width - padding
    scaling_factor = new_image_width / img_width

    scaled_img_width = ceil(img_width * scaling_factor)
    scaled_img_height = ceil(img_height * scaling_factor)

    cell_height = scaled_img_height + padding

    number_of_rows = ceil(len(images) / images_per_row)
    frame_height = cell_height * number_of_rows - padding

    new_im = Image.new('RGB', (frame_width, frame_height))
    
    x_cord = 0
    for num, im in enumerate(images):
        if num % images_per_row == 0:
            x_cord = 0
        im = Image.open(im)
        im.thumbnail((scaled_img_width, scaled_img_height))
        y_cord = (num // images_per_row) * cell_height
        new_im.paste(im, (x_cord, y_cord))
        x_cord += cell_width

    # using PNG because JPEG is lossy
    new_im.save("Collage.png", "PNG", quality = 80, optimize = True, progressive = True)

width, height = Image.open(listofimages[0]).size # get size of images (assume all same size)
create_collage(5, width, height, 20, listofimages)
Jake Ireland
  • 543
  • 4
  • 11