|
| 1 | +from PIL import Image |
| 2 | +# Open image using Image module |
| 3 | + |
| 4 | +import tkinter as tk |
| 5 | +from tkinter import filedialog |
| 6 | + |
| 7 | +# 1600 = hd (high definition, for social media) |
| 8 | +# 1920 x 1280 = fhd (full hd) |
| 9 | +# 2560 x 1440 = qhd (quad hd, aka 2k) |
| 10 | +# 3840 x 2160 = 4k |
| 11 | +# 7680 x 4320 = 8k |
| 12 | +res_str = "4k" |
| 13 | + |
| 14 | +res_str_list = ["hd", "fhd", "qhd", "4k", "8k", "10k", "12k", "14k", "max"] |
| 15 | +res_list = [1600, 1920, 2560, 3840, 7680, 10000, 12000, 14000, 99999] |
| 16 | +max_final_image_dimension = res_list[res_str_list.index(res_str)] |
| 17 | + |
| 18 | +crop_shift = 283 # pixels to remove from one side of each image. The side affected depends on pairing orientation. |
| 19 | +image_merge = 1 # either merge the images to one, or save them separately, just resized |
| 20 | +if not image_merge: |
| 21 | + crop_shift = 0 |
| 22 | + |
| 23 | +save = 1 # if save is off, just display the image for a review |
| 24 | +show = 1 # only show final image(s) if this is on of if it is not saving |
| 25 | +image_rotate = 0 # value here is number of quarter turns (range of integers 1-3, or 0 for off). |
| 26 | +# Note that the flips occur after the rotation |
| 27 | +A_flip_H = 0 |
| 28 | +A_flip_V = 0 |
| 29 | +B_flip_H = 0 |
| 30 | +B_flip_V = 0 |
| 31 | +A_first_override = 0 |
| 32 | +orientation_override = 0 # 1 for horizontal arrangement, -1 for vertical. 0 for automatic. |
| 33 | +duplicated = 0 # set to 1 to duplicate a single image |
| 34 | + |
| 35 | +root = tk.Tk() |
| 36 | +root.withdraw() |
| 37 | + |
| 38 | +image_name = filedialog.askopenfilename(title='select', filetypes=[("image", ".png"), ("image", ".jpg")]) |
| 39 | +base_image_extension = image_name[-4:len(image_name)] |
| 40 | + |
| 41 | +if duplicated: |
| 42 | + image_name_A = image_name |
| 43 | + image_name_B = image_name |
| 44 | + duplicated = image_merge |
| 45 | +elif image_name[-5] == "B": |
| 46 | + A_first = 0 if not A_first_override else 1 |
| 47 | + image_name_B = image_name |
| 48 | + base_image_name = image_name[0:(len(image_name) - 6)] |
| 49 | + image_name_A = base_image_name + base_image_extension |
| 50 | +else: |
| 51 | + A_first = 1 |
| 52 | + image_name_A = image_name |
| 53 | + base_image_name = image_name[0:(len(image_name) - 4)] |
| 54 | + image_name_B = base_image_name + "-B" + base_image_extension |
| 55 | + |
| 56 | +image_A = Image.open(image_name_A) |
| 57 | +image_B = Image.open(image_name_B) |
| 58 | +if image_rotate == 1: |
| 59 | + image_A = image_A.transpose(Image.Transpose.ROTATE_90) |
| 60 | + image_B = image_B.transpose(Image.Transpose.ROTATE_90) |
| 61 | +elif image_rotate == 2: |
| 62 | + image_A = image_A.transpose(Image.Transpose.ROTATE_180) |
| 63 | + image_B = image_B.transpose(Image.Transpose.ROTATE_180) |
| 64 | +elif image_rotate == 3: |
| 65 | + image_A = image_A.transpose(Image.Transpose.ROTATE_270) |
| 66 | + image_B = image_B.transpose(Image.Transpose.ROTATE_270) |
| 67 | +if A_flip_H: |
| 68 | + image_A = image_A.transpose(Image.Transpose.FLIP_LEFT_RIGHT) |
| 69 | +if A_flip_V: |
| 70 | + image_A = image_A.transpose(Image.Transpose.FLIP_TOP_BOTTOM) |
| 71 | +if B_flip_H: |
| 72 | + image_B = image_B.transpose(Image.Transpose.FLIP_LEFT_RIGHT) |
| 73 | +if B_flip_V: |
| 74 | + image_B = image_B.transpose(Image.Transpose.FLIP_TOP_BOTTOM) |
| 75 | + |
| 76 | +width, height = image_A.size |
| 77 | +AR = height/width |
| 78 | +print(f"starting image dimensions = {width} x {height}, AR = {round(height/width, 3)}") |
| 79 | + |
| 80 | +X_pair = False |
| 81 | +Y_pair = False |
| 82 | +if image_merge: |
| 83 | + if (height / width >= 1.125 or orientation_override == 1) and not orientation_override == -1: |
| 84 | + # if it's a taller image, set up side by side. |
| 85 | + # But if closer to square, keep vertical arrangement |
| 86 | + max_image_dim = max(2 * (width - crop_shift), height) |
| 87 | + X_pair = True |
| 88 | + else: |
| 89 | + max_image_dim = max(2 * (height - crop_shift), width) |
| 90 | + Y_pair = True |
| 91 | +else: |
| 92 | + max_image_dim = max(width, height) |
| 93 | + |
| 94 | +crop_X = crop_shift if X_pair else 0 |
| 95 | +crop_Y = crop_shift if Y_pair else 0 |
| 96 | + |
| 97 | +scale_factor = max_final_image_dimension / max_image_dim |
| 98 | + |
| 99 | +if duplicated: |
| 100 | + image1 = image_A |
| 101 | + image2 = image_B |
| 102 | + suffix_abba = "DD" |
| 103 | +elif A_first: |
| 104 | + image1 = image_A |
| 105 | + image2 = image_B |
| 106 | + suffix_abba = "-AB" |
| 107 | +else: |
| 108 | + image1 = image_B |
| 109 | + image2 = image_A |
| 110 | + suffix_abba = "-BA" |
| 111 | + |
| 112 | +if crop_shift > 0: |
| 113 | + left = 0 |
| 114 | + top = 0 |
| 115 | + right = width - left - crop_X |
| 116 | + bottom = height - crop_Y |
| 117 | + |
| 118 | + image1 = image1.crop((left, top, right, bottom)) |
| 119 | + image2 = image2.crop((left + crop_X, top + crop_Y, width - left, height)) |
| 120 | + width, height = image1.size |
| 121 | + print(f"cropped image dimensions = {width} x {height}") |
| 122 | + |
| 123 | +if scale_factor < 1.0: |
| 124 | + image1R = image1.resize((round(width * scale_factor), round(height * scale_factor))) |
| 125 | + image2R = image2.resize((round(width * scale_factor), round(height * scale_factor))) |
| 126 | + width, height = image1R.size |
| 127 | + print(f"resized image dimensions = {width} x {height}") |
| 128 | +else: |
| 129 | + image1R = image1 |
| 130 | + image2R = image2 |
| 131 | + print(f"desired size exceeds image dimensions, no resize necessary.") |
| 132 | + res_str = "max" |
| 133 | + |
| 134 | +if image_merge: |
| 135 | + if X_pair: |
| 136 | + new_image = Image.new('RGB', (2 * image1R.size[0], image1R.size[1]), (250, 250, 250)) |
| 137 | + new_image.paste(image1R, (0, 0)) |
| 138 | + new_image.paste(image2R, (image2R.size[0], 0)) |
| 139 | + else: |
| 140 | + new_image = Image.new('RGB', (image1R.size[0], 2 * image1R.size[1]), (250, 250, 250)) |
| 141 | + new_image.paste(image1R, (0, 0)) |
| 142 | + new_image.paste(image2R, (0, image2R.size[1])) |
| 143 | + |
| 144 | + width, height = new_image.size |
| 145 | + print(f"merged image dimensions = {width} x {height}, AR = {round(height/width, 3)}") |
| 146 | + if save: |
| 147 | + new_image.save(base_image_name + suffix_abba + "-" + res_str + ".png", "PNG") |
| 148 | + if show or not save: |
| 149 | + new_image.show() |
| 150 | +else: |
| 151 | + if save: |
| 152 | + image1R.save(base_image_name + "-A-" + res_str + ".png", "PNG") |
| 153 | + image2R.save(base_image_name + "-B-" + res_str + ".png", "PNG") |
| 154 | + else: |
| 155 | + image1R.show() |
| 156 | + image2R.show() |
| 157 | +# --------------------------------------------------------------- |
0 commit comments