BetterTwitFix/combineImg/__init__.py
2022-05-26 15:01:12 +01:00

132 lines
No EOL
5 KiB
Python

from pickletools import optimize
from turtle import down
from weakref import finalize
from PIL import Image, ImageOps, ImageFilter
from requests import get
from io import BytesIO
import base64
from multiprocessing.pool import ThreadPool
from time import time as timer
# find the highest res image in an array of images
def findImageWithMostPixels(imageArray):
maxPixels = 0
maxImage = None
for image in imageArray:
pixels = image.size[0] * image.size[1]
if pixels > maxPixels:
maxPixels = pixels
maxImage = image
return maxImage
def getTotalImgSize(imageArray): # take the image with the most pixels, multiply it by the number of images, and return the width and height
maxImage = findImageWithMostPixels(imageArray)
if (len(imageArray) == 1):
return (maxImage.size[0], maxImage.size[1])
elif (len(imageArray) == 2):
return (maxImage.size[0] * 2, maxImage.size[1])
else:
return (maxImage.size[0] * 2, maxImage.size[1]*2)
def scaleImageIterable(args):
image = args[0]
targetWidth = args[1]
targetHeight = args[2]
pad=args[3]
if pad:
image = image.convert('RGBA')
newImg = ImageOps.pad(image, (targetWidth, targetHeight),color=(0, 0, 0, 0))
else:
newImg = ImageOps.fit(image, (targetWidth, targetHeight)) # scale + crop
return newImg
def scaleAllImagesToSameSize(imageArray,targetWidth,targetHeight,pad=True): # scale all images in the array to the same size, preserving aspect ratio
newImageArray = []
newImageArray=[scaleImageIterable([image,targetWidth,targetHeight,pad]) for image in imageArray]
return newImageArray
def blurImage(image, radius):
return image.filter(ImageFilter.GaussianBlur(radius=radius))
def combineImages(imageArray, totalWidth, totalHeight,pad=True):
x = 0
y = 0
if (len(imageArray) == 1): # if there is only one image, just return it
return imageArray[0]
# image generation is needed
topImg = findImageWithMostPixels(imageArray)
newImage = Image.new("RGBA", (totalWidth, totalHeight),(0, 0, 0, 0))
imageArray = scaleAllImagesToSameSize(imageArray,topImg.size[0],topImg.size[1],pad)
if (len(imageArray) == 2): # if there are two images, combine them horizontally
for image in imageArray:
newImage.paste(image, (x, y))
x += image.size[0]
elif (len(imageArray) == 3): # the elusive 3 image upload
# if there are three images, combine the first two horizontally, then combine the last one vertically
imageArray[2] = scaleAllImagesToSameSize([imageArray[2]],totalWidth,topImg.size[1],pad)[0] # take the last image, treat it like an image array and scale it to the total width, but same height as all individual images
for image in imageArray[0:2]:
newImage.paste(image, (x, y))
x += image.size[0]
y += imageArray[0].size[1]
x = 0
newImage.paste(imageArray[2], (x, y))
elif (len(imageArray) == 4): # if there are four images, combine the first two horizontally, then combine the last two vertically
for image in imageArray[0:2]:
newImage.paste(image, (x, y))
x += image.size[0]
y += imageArray[0].size[1]
x = 0
for image in imageArray[2:4]:
newImage.paste(image, (x, y))
x += image.size[0]
else:
for image in imageArray:
newImage.paste(image, (x, y))
x += image.size[0]
return newImage
def saveImage(image, name):
image.save(name)
# combine up to four images into a single image
def genImage(imageArray):
totalSize=getTotalImgSize(imageArray)
combined = combineImages(imageArray, *totalSize)
combinedBG = combineImages(imageArray, *totalSize,False)
combinedBG = blurImage(combinedBG,50)
finalImg = Image.alpha_composite(combinedBG,combined)
finalImg = ImageOps.pad(finalImg, findImageWithMostPixels(imageArray).size,color=(0, 0, 0, 0))
finalImg = finalImg.convert('RGB')
return finalImg
def downloadImage(url):
return Image.open(BytesIO(get(url).content))
def genImageFromURL(urlArray):
# this method avoids storing the images in disk, instead they're stored in memory
# no cache means that they'll have to be downloaded again if the image is requested again
# TODO: cache?
start = timer()
imageArray = ThreadPool(8).map(downloadImage,urlArray)
print(f"Images downloaded in: {timer() - start}s")
start = timer()
finalImg = genImage(imageArray)
print(f"Image generated in: {timer() - start}s")
return finalImg
def lambda_handler(event, context):
# TODO implement
images = event["queryStringParameters"].get("imgs","").split(",")
combined = genImageFromURL(images)
buffered = BytesIO()
combined.save(buffered,format="JPEG",quality=60)
combined_str=base64.b64encode(buffered.getvalue()).decode('ascii')
return {
'statusCode': 200,
"headers":
{
"Content-Type": "image/jpeg"
},
'body': combined_str,
'isBase64Encoded': True
}