getting it to git
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
8
.idea/ChristianPostMaker.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.7" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/ChristianPostMaker.iml" filepath="$PROJECT_DIR$/.idea/ChristianPostMaker.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
Fonts.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
class Fonts:
|
||||||
|
fonts_path: str
|
||||||
|
fonts_size: int
|
||||||
|
fonts_chars_limit: int
|
||||||
|
|
||||||
|
def __init__(self, fonts_path, fonts_size, fonts_chars_limit):
|
||||||
|
self.fonts_path = fonts_path
|
||||||
|
self.fonts_size = fonts_size
|
||||||
|
self.fonts_chars_limit = fonts_chars_limit
|
||||||
BIN
customers/0-0.jpg
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
customers/1-0.jpg
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
customers/test1/0-0.jpg
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
customers/test1/1-0.jpg
Normal file
|
After Width: | Height: | Size: 220 KiB |
45
darkenVideos.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import moviepy.video.io.VideoFileClip as vfc
|
||||||
|
import os
|
||||||
|
from moviepy import video
|
||||||
|
|
||||||
|
|
||||||
|
def generate_darken_video(video_file, output_path):
|
||||||
|
video_clip = (vfc.VideoFileClip(video_file, audio=False)
|
||||||
|
.without_audio())
|
||||||
|
|
||||||
|
# Save the final video
|
||||||
|
darken_clip = video_clip.fl_image(darken)
|
||||||
|
darken_clip.write_videofile(output_path,
|
||||||
|
threads=8,
|
||||||
|
codec="libx264")
|
||||||
|
# Clean up the temporary files
|
||||||
|
darken_clip.close()
|
||||||
|
|
||||||
|
|
||||||
|
# A defined function to darken the frames
|
||||||
|
def darken(frame):
|
||||||
|
return frame * DARK
|
||||||
|
|
||||||
|
|
||||||
|
def generate_darken_videos(video_folder, output_folder):
|
||||||
|
# Get a list of video files in the specified folder
|
||||||
|
video_files = [f"{video_folder}/{file}" for file in os.listdir(video_folder) if file.endswith(".mp4")]
|
||||||
|
for video_file in video_files:
|
||||||
|
video_num = video_file.split('/')
|
||||||
|
video_num = video_num[len(video_num) - 1].split('.')
|
||||||
|
video_num = video_num[0]
|
||||||
|
|
||||||
|
generate_darken_video(video_file, f"{output_folder}/{video_num}.mp4")
|
||||||
|
|
||||||
|
|
||||||
|
video_folder = "E:/Bots/VideoMaker/videos/original/new ones"
|
||||||
|
output_folder = "E:/Bots/VideoMaker/videos"
|
||||||
|
DARK = 0.8
|
||||||
|
generate_darken_videos(video_folder, output_folder)
|
||||||
|
# Specific video
|
||||||
|
# video_file = "E:/Bots/VideoMaker/videos/original/7.mp4"
|
||||||
|
# output_path = "E:/Bots/VideoMaker/videos/darken 40%/7.mp4"
|
||||||
|
# generate_darken_video(video_file, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
201
ffmpeg.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import os
|
||||||
|
import random
|
||||||
|
import subprocess
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import json_handler
|
||||||
|
import verse_handler
|
||||||
|
import Fonts
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
|
||||||
|
def create_dirs(output_folder, customer_name, posts=True):
|
||||||
|
# create a folder for this customer if it doesn't exist
|
||||||
|
output_path = f"{output_folder}/{customer_name}"
|
||||||
|
if not os.path.exists(output_path):
|
||||||
|
os.makedirs(output_path)
|
||||||
|
# Create folder inside for images
|
||||||
|
if not os.path.exists(f"{output_path}/verse_images"):
|
||||||
|
os.makedirs(f"{output_path}/verse_images")
|
||||||
|
if posts and not os.path.exists(f"{output_path}/post_images"):
|
||||||
|
os.makedirs(f"{output_path}/post_images")
|
||||||
|
return output_path
|
||||||
|
|
||||||
|
|
||||||
|
def create_videos(video_folder, audio_folder, json_file, fonts_dir, output_folder, text_source_font, image_file,
|
||||||
|
customer_name, number_of_videos, fonts: Fonts, posts=True):
|
||||||
|
run_time_average = 0
|
||||||
|
if number_of_videos > 1:
|
||||||
|
start_time_total = time.time()
|
||||||
|
|
||||||
|
json_data = json_handler.get_data(json_file)
|
||||||
|
verses: str = json_data[0]
|
||||||
|
refs: str = json_data[1]
|
||||||
|
|
||||||
|
videos_num = list()
|
||||||
|
audios_num = list()
|
||||||
|
fonts_num = list()
|
||||||
|
|
||||||
|
# Get lists of video and audio files in the specified folders
|
||||||
|
video_files = [f"{video_folder}/{file}" for file in os.listdir(video_folder) if file.endswith(".mp4")]
|
||||||
|
audio_files = [f"{audio_folder}/{file}" for file in os.listdir(audio_folder) if file.endswith(".mp3")]
|
||||||
|
random_for_video = random.randint(0, len(video_files) - 1)
|
||||||
|
random_for_audio = random.randint(0, len(audio_files) - 1)
|
||||||
|
random_for_font = random.randint(0, len(fonts.fonts_path) - 1)
|
||||||
|
for i in range(number_of_videos):
|
||||||
|
videos_num.append((random_for_video + i) % len(video_files))
|
||||||
|
audios_num.append((random_for_audio + i) % len(audio_files))
|
||||||
|
fonts_num.append((random_for_font + i) % len(fonts.fonts_path))
|
||||||
|
random.shuffle(videos_num)
|
||||||
|
random.shuffle(audios_num)
|
||||||
|
random.shuffle(fonts_num)
|
||||||
|
|
||||||
|
# Creating folder for customer
|
||||||
|
output_path = create_dirs(output_folder, customer_name, posts)
|
||||||
|
|
||||||
|
for i in range(number_of_videos):
|
||||||
|
start_time = time.time()
|
||||||
|
print(f"Creating Video #{i}")
|
||||||
|
|
||||||
|
text_verse = verses[i]
|
||||||
|
text_source = refs[i]
|
||||||
|
|
||||||
|
# Choose a random video file from the list
|
||||||
|
random_video_num = videos_num[0]
|
||||||
|
del videos_num[0]
|
||||||
|
video_file = video_files[random_video_num]
|
||||||
|
# video_file = f"{video_folder}/30.mp4"
|
||||||
|
|
||||||
|
# Choose a random font from list
|
||||||
|
random_font_num = fonts_num[0]
|
||||||
|
del fonts_num[0]
|
||||||
|
font_file = fonts.fonts_path[random_font_num]
|
||||||
|
font_size = fonts.fonts_size[random_font_num]
|
||||||
|
font_chars = fonts.fonts_chars_limit[random_font_num]
|
||||||
|
|
||||||
|
# Choose a random audio file from the list
|
||||||
|
random_audio_num = audios_num[0]
|
||||||
|
del audios_num[0]
|
||||||
|
audio_file = audio_files[random_audio_num]
|
||||||
|
|
||||||
|
# remove chars from versesource for the name
|
||||||
|
text_source_for_image = text_source.replace(":", "").rstrip('\n')
|
||||||
|
text_source_for_name = text_source_for_image.replace(' ', '')
|
||||||
|
|
||||||
|
file_name = f"/{i}-{text_source_for_name}_{random_video_num}_{random_audio_num}_{random_font_num}.mp4"
|
||||||
|
|
||||||
|
create_video(text_verse=text_verse, text_source=text_source, text_source_font=text_source_font,
|
||||||
|
text_source_for_image=text_source_for_image,
|
||||||
|
video_file=video_file, audio_file=audio_file, image_file=image_file,
|
||||||
|
font_file=font_file, font_size=font_size, font_chars=font_chars,
|
||||||
|
posts=posts,
|
||||||
|
output_path=output_path, file_name=file_name)
|
||||||
|
|
||||||
|
end_time = time.time()
|
||||||
|
run_time = end_time - start_time
|
||||||
|
run_time_average += run_time
|
||||||
|
print(f"\033[0;34m DONE #{i}, Run time:", round(run_time, 2), "seconds! \033[0m", output_path)
|
||||||
|
|
||||||
|
if number_of_videos > 1:
|
||||||
|
run_time_average /= number_of_videos
|
||||||
|
end_time_total = time.time()
|
||||||
|
run_time_total = end_time_total - start_time_total
|
||||||
|
print(f"\n\033[0;32mDone making {number_of_videos} videos for {customer_name}!"
|
||||||
|
f"\nTotal run time:", round(run_time_total, 2), "seconds!"
|
||||||
|
f"\nAverage run time:", round(run_time_average, 2),
|
||||||
|
"seconds = ", round(run_time_average / 60, 2), " minutes! \033[0m")
|
||||||
|
|
||||||
|
|
||||||
|
def create_video(text_verse, text_source, text_source_font, text_source_for_image, video_file, audio_file, image_file,
|
||||||
|
font_file, font_size, font_chars, output_path, file_name, posts=True):
|
||||||
|
# Coordinates of logo image and text2 clips
|
||||||
|
image_y = 1600
|
||||||
|
text2_y = 1300
|
||||||
|
|
||||||
|
# Get the video size
|
||||||
|
result = subprocess.run(
|
||||||
|
['ffprobe', '-v', 'error', '-show_entries', 'stream=width,height', '-of', 'csv=p=0:s=x', video_file],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
video_size = re.findall('\d+', result.stdout.decode())[0:2]
|
||||||
|
video_width, video_height = map(int, video_size)
|
||||||
|
|
||||||
|
# Get video duration
|
||||||
|
ffprobe_command = f'ffprobe -i "{video_file}" -show_entries format=duration -v quiet -of csv="p=0"'
|
||||||
|
video_duration = subprocess.check_output(ffprobe_command, shell=True)
|
||||||
|
video_duration = float(video_duration.decode('utf-8').strip())
|
||||||
|
|
||||||
|
# Set the start time of text
|
||||||
|
text_start_time = 1
|
||||||
|
|
||||||
|
# Create image of verse
|
||||||
|
created_verse_image = verse_handler.create_image(text_verse, font_file, font_size, font_chars,
|
||||||
|
(int(video_width), int(video_height / 2)), output_path,
|
||||||
|
text_source_for_image)
|
||||||
|
|
||||||
|
# fix bug that ':' and beyond wasn't showing on screen
|
||||||
|
text_source = text_source.replace(':', '\:')
|
||||||
|
output_path += f"/{file_name}"
|
||||||
|
# FFMPEG command to overlay images and text onto input video
|
||||||
|
ffmpeg_command = (f'ffmpeg -y -loop 1 -i "{image_file}" -i "{audio_file}" '
|
||||||
|
f'-i "{video_file}" -i "{created_verse_image}" -r 24 -filter_complex '
|
||||||
|
f'"[2:v][0:v]overlay=(W-w)/2:{image_y}[v1]; '
|
||||||
|
# f'[v1]drawtext=fontfile={selected_font}:text=\'{text_verse}\':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=60:fontcolor=white:'
|
||||||
|
# f'enable=\'between(t,{text_start_time},{video_duration})\'[v2]; '
|
||||||
|
f'[v1]drawtext=fontfile=\'{text_source_font}\':text=\'{text_source}\':x=(w-text_w)/2:y={text2_y}:fontsize=42:fontcolor=white:'
|
||||||
|
f'enable=\'between(t,{text_start_time},{video_duration})\'[v2]; '
|
||||||
|
f'[v2][3:v]overlay=(W-w)/2:{video_height}/4:enable=\'between(t,{text_start_time},{video_duration})\'[v3]" '
|
||||||
|
f'-t {video_duration} -map "[v3]" -map 1:a -c:v libx264 -preset veryfast -crf 18 -c:a copy "{output_path}"')
|
||||||
|
|
||||||
|
# WITHOUT LOGO
|
||||||
|
# ffmpeg_command = (f'ffmpeg -y -i "{audio_file}" '
|
||||||
|
# f'-i "{video_file}" -i "{created_verse_image}" -r 24 -filter_complex '
|
||||||
|
# # f'[v1]drawtext=fontfile={selected_font}:text=\'{text_verse}\':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=60:fontcolor=white:'
|
||||||
|
# # f'enable=\'between(t,{text_start_time},{video_duration})\'[v2]; '
|
||||||
|
# f'"drawtext=fontfile=\'{text_source_font}\':text=\'{text_source}\':x=(w-text_w)/2:y={text2_y}:fontsize=42:fontcolor=white:'
|
||||||
|
# f'enable=\'between(t,{text_start_time},{video_duration})\'[v1]; '
|
||||||
|
# f'[v1][2:v]overlay=(W-w)/2:{video_height}/4:enable=\'between(t,{text_start_time},{video_duration})\'[v2]" '
|
||||||
|
# f'-t {video_duration} -map "[v2]" -map 0:a -c:v libx264 -preset veryfast -crf 18 -c:a copy "{output_path}"')
|
||||||
|
|
||||||
|
# Run FFMPEG command
|
||||||
|
subprocess.call(ffmpeg_command, shell=True)
|
||||||
|
|
||||||
|
# if posts:
|
||||||
|
# verse_handler.create_post_images(video_path=output_path, output_folder=output_path.strip(f"/{file_name}"),
|
||||||
|
# verse_image_path=created_verse_image, text_source=text_source)
|
||||||
|
|
||||||
|
|
||||||
|
def create_post_images(video_path: str, verse_image_path, text_source, output_folder):
|
||||||
|
# Open the video file
|
||||||
|
video = cv2.VideoCapture(video_path)
|
||||||
|
|
||||||
|
# Get the frame rate of the video
|
||||||
|
fps = int(video.get(cv2.CAP_PROP_FPS))
|
||||||
|
|
||||||
|
# Set the time in seconds to extract a frame from
|
||||||
|
time_in_seconds = 2
|
||||||
|
|
||||||
|
# Calculate the frame index to extract
|
||||||
|
frame_index = time_in_seconds * fps
|
||||||
|
|
||||||
|
# Set the output image size
|
||||||
|
output_size = (1080, 1080)
|
||||||
|
|
||||||
|
# Loop through the video frames until we reach the desired frame
|
||||||
|
for i in range(frame_index):
|
||||||
|
ret, frame = video.read()
|
||||||
|
|
||||||
|
# Crop the middle square of the frame
|
||||||
|
height, width, channels = frame.shape
|
||||||
|
y = 325
|
||||||
|
cropped_frame = frame[y:y + 1440, 0:width]
|
||||||
|
|
||||||
|
# Resize the cropped frame to the output size
|
||||||
|
# resized_frame = cv2.resize(cropped_frame, output_size)
|
||||||
|
|
||||||
|
# Save the frame as an image
|
||||||
|
output_name = video_path.split('/')
|
||||||
|
output_name = output_name[len(output_name) - 1].strip(".mp4")
|
||||||
|
cv2.imwrite(f"{output_folder}/post_images/{output_name}.jpg", cropped_frame)
|
||||||
|
|
||||||
|
# Release the video file
|
||||||
|
video.release()
|
||||||
50
helper_images.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
from PIL import Image, ImageEnhance
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def darken_images(images_folder, output_folder):
|
||||||
|
# Set desired darkness
|
||||||
|
dark = 0.5
|
||||||
|
|
||||||
|
# Loop through all the images in the directory
|
||||||
|
for filename in os.listdir(images_folder):
|
||||||
|
if filename.endswith(".jpg") or filename.endswith(".png"):
|
||||||
|
# Open the image
|
||||||
|
filepath = os.path.join(images_folder, filename)
|
||||||
|
img = Image.open(filepath)
|
||||||
|
|
||||||
|
# Create an enhancer object for the image
|
||||||
|
enhancer = ImageEnhance.Brightness(img)
|
||||||
|
|
||||||
|
# Reduce the brightness by a factor of 'dark'
|
||||||
|
dark_img = enhancer.enhance(dark)
|
||||||
|
|
||||||
|
# Save the cropped image
|
||||||
|
dark_img.save(f"{output_folder}/{filename}")
|
||||||
|
|
||||||
|
|
||||||
|
def cut_images(images_folder, output_folder):
|
||||||
|
# Set the target size
|
||||||
|
target_size = (1080, 1350)
|
||||||
|
|
||||||
|
# Loop through all the images in the directory
|
||||||
|
for filename in os.listdir(images_folder):
|
||||||
|
if filename.endswith(".jpg") or filename.endswith(".png"):
|
||||||
|
# Open the image
|
||||||
|
filepath = os.path.join(images_folder, filename)
|
||||||
|
img = Image.open(filepath)
|
||||||
|
|
||||||
|
# Get the size of the image
|
||||||
|
width, height = img.size
|
||||||
|
|
||||||
|
# Calculate the coordinates for cropping
|
||||||
|
left = (width - target_size[0]) // 2
|
||||||
|
top = (height - target_size[1]) // 2
|
||||||
|
right = left + target_size[0]
|
||||||
|
bottom = top + target_size[1]
|
||||||
|
|
||||||
|
# Crop the image
|
||||||
|
img = img.crop((left, top, right, bottom))
|
||||||
|
|
||||||
|
# Save the cropped image
|
||||||
|
img.save(f"{output_folder}/{filename}")
|
||||||
9
json_handler.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(json_file):
|
||||||
|
with open(f'{json_file}', 'r', encoding='utf-8') as f:
|
||||||
|
jsonData = json.load(f)
|
||||||
|
verses: str = jsonData['verses']
|
||||||
|
refs: str = jsonData['references']
|
||||||
|
return verses, refs
|
||||||
19
main.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import post_handler
|
||||||
|
import helper_images
|
||||||
|
|
||||||
|
# Define the paths and values to everything
|
||||||
|
number_of_posts = 2
|
||||||
|
images_folder = "C:/Bots/ChristianPostMaker/sources/images/cropped/darken"
|
||||||
|
text_file = "C:/Bots/ChristianPostMaker/sources/quotes.txt"
|
||||||
|
font_dir = "C:/Users/samla/AppData/Local/Microsoft/Windows/Fonts/MouldyCheeseRegular-WyMWG.ttf"
|
||||||
|
output_folder = "C:/Bots/ChristianPostMaker/customers"
|
||||||
|
logo_file = "C:/Bots/ChristianPostMaker/sources/logo.png"
|
||||||
|
customer_name = "test1"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# helper_images.cut_images(images_folder, f"{images_folder}/cropped")
|
||||||
|
# helper_images.darken_images(images_folder, f"{images_folder}/darken")
|
||||||
|
post_handler.create_posts(images_folder=images_folder, text_file=text_file,
|
||||||
|
font_dir=font_dir, output_folder=output_folder,
|
||||||
|
logo_file=logo_file, customer_name=customer_name, number_of_posts=number_of_posts)
|
||||||
143
post_handler.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import os
|
||||||
|
import random
|
||||||
|
import textwrap
|
||||||
|
import time
|
||||||
|
from string import ascii_letters
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance
|
||||||
|
|
||||||
|
import json_handler
|
||||||
|
|
||||||
|
|
||||||
|
def create_dirs(output_folder, customer_name):
|
||||||
|
# create a folder for this customer if it doesn't exist
|
||||||
|
output_path = f"{output_folder}/{customer_name}"
|
||||||
|
if not os.path.exists(output_path):
|
||||||
|
os.makedirs(output_path)
|
||||||
|
# Create folder inside for images
|
||||||
|
if not os.path.exists(f"{output_path}/verse_images"):
|
||||||
|
os.makedirs(f"{output_path}/verse_images")
|
||||||
|
return output_path
|
||||||
|
|
||||||
|
|
||||||
|
def create_posts(images_folder, text_file, font_dir, output_folder, customer_name, number_of_posts, logo_file: str = None):
|
||||||
|
run_time_average = 0
|
||||||
|
if number_of_posts > 1:
|
||||||
|
start_time_total = time.time()
|
||||||
|
|
||||||
|
# json_data = json_handler.get_data(json_file)
|
||||||
|
# verses: str = json_data[0]
|
||||||
|
# refs: str = json_data[1]
|
||||||
|
|
||||||
|
quotes = ["test1", "test2"]
|
||||||
|
|
||||||
|
|
||||||
|
# Get list of photos in the specified folder and shuffle it
|
||||||
|
image_num = list()
|
||||||
|
image_files = [f"{images_folder}/{file}" for file in os.listdir(images_folder) if file.endswith(".jpg") or file.endswith(".png")]
|
||||||
|
random_for_image = random.randint(0, len(image_files) - 1)
|
||||||
|
for i in range(number_of_posts):
|
||||||
|
image_num.append((random_for_image + i) % len(image_files))
|
||||||
|
random.shuffle(image_num)
|
||||||
|
|
||||||
|
# Creating folder for customer
|
||||||
|
output_path = create_dirs(output_folder, customer_name)
|
||||||
|
|
||||||
|
for i in range(number_of_posts):
|
||||||
|
start_time = time.time()
|
||||||
|
print(f"Creating Post #{i}")
|
||||||
|
|
||||||
|
text = quotes[i]
|
||||||
|
|
||||||
|
# Choose a random image file from the list
|
||||||
|
random_image_num = image_num[0]
|
||||||
|
del image_num[0]
|
||||||
|
image_file = image_files[random_image_num]
|
||||||
|
file_name = f"/{i}-{random_image_num}.jpg"
|
||||||
|
create_post(image_file=image_file, text=text,
|
||||||
|
font_dir=font_dir, output_path=output_path, file_name=file_name,
|
||||||
|
logo_file=logo_file, customer_name=customer_name)
|
||||||
|
|
||||||
|
end_time = time.time()
|
||||||
|
run_time = end_time - start_time
|
||||||
|
run_time_average += run_time
|
||||||
|
print(f"\033[0;34m DONE #{i}, Run time:", round(run_time, 2), "seconds! \033[0m", output_path)
|
||||||
|
|
||||||
|
if number_of_posts > 1:
|
||||||
|
run_time_average /= number_of_posts
|
||||||
|
end_time_total = time.time()
|
||||||
|
run_time_total = end_time_total - start_time_total
|
||||||
|
print(f"\n\033[0;32mDone making {number_of_posts} posts for {customer_name}!"
|
||||||
|
f"\nTotal run time:", round(run_time_total, 2), "seconds!"
|
||||||
|
f"\nAverage run time:", round(run_time_average, 2),
|
||||||
|
"seconds = ", round(run_time_average / 60, 2), " minutes! \033[0m")
|
||||||
|
|
||||||
|
|
||||||
|
def create_post(image_file, text, font_dir, output_path, file_name, logo_file, customer_name):
|
||||||
|
# Open specific image
|
||||||
|
img = Image.open(image_file)
|
||||||
|
|
||||||
|
# Load selected font
|
||||||
|
font = ImageFont.truetype(font=f'{font_dir}', size=75)
|
||||||
|
|
||||||
|
# Create DrawText object
|
||||||
|
draw = ImageDraw.Draw(im=img)
|
||||||
|
|
||||||
|
# Define our text:
|
||||||
|
# Calculate the average length of a single character of our font.
|
||||||
|
# Note: this takes into account the specific font and font size.
|
||||||
|
avg_char_width = sum(font.getsize(char)[0] for char in ascii_letters) / len(ascii_letters)
|
||||||
|
|
||||||
|
# Translate this average length into a character count
|
||||||
|
max_char_count = int(img.size[0] * .718 / avg_char_width)
|
||||||
|
|
||||||
|
# Create a wrapped text object using scaled character count
|
||||||
|
new_text = textwrap.fill(text=text, width=max_char_count)
|
||||||
|
|
||||||
|
# Define the positions of logo and text
|
||||||
|
x_logo = 0
|
||||||
|
y_logo = 1100
|
||||||
|
x_text = img.size[0] / 2
|
||||||
|
y_text = img.size[1] / 2
|
||||||
|
position = (x_text, y_text)
|
||||||
|
|
||||||
|
# Draw the shadow text
|
||||||
|
shadow_color = (0, 0, 0, 128)
|
||||||
|
shadow_position = (x_text+5, y_text+5)
|
||||||
|
draw.text(shadow_position, text, font=font, fill=shadow_color, anchor='mm')
|
||||||
|
|
||||||
|
# Add main text to the image
|
||||||
|
draw.text(position, text=new_text, font=font, fill=(255, 255, 255, 255), anchor='mm',
|
||||||
|
align='center')
|
||||||
|
|
||||||
|
if logo_file is not None:
|
||||||
|
# Open logo file
|
||||||
|
img_logo = Image.open(logo_file)
|
||||||
|
|
||||||
|
# Reduce the alpha of the overlay image by 50%
|
||||||
|
alpha = 0.5
|
||||||
|
enhancer = ImageEnhance.Brightness(img_logo)
|
||||||
|
img_logo_darken = enhancer.enhance(alpha)
|
||||||
|
|
||||||
|
# Create a new image object with the same size as the background image
|
||||||
|
img_with_logo = Image.new('RGBA', img.size, (0, 0, 0, 0))
|
||||||
|
|
||||||
|
# Draw the background image onto the new image
|
||||||
|
img_with_logo.paste(img, (0, 0))
|
||||||
|
|
||||||
|
# Draw the overlay image onto the new image
|
||||||
|
img_with_logo.paste(img_logo_darken, (int(x_logo), int(y_logo)), mask=img_logo_darken)
|
||||||
|
|
||||||
|
# Convert from RGBA to RGB
|
||||||
|
img_with_logo_rgb = img_with_logo.convert("RGB")
|
||||||
|
|
||||||
|
# Save the image
|
||||||
|
img_with_logo_rgb.save(f"{output_path}/{file_name}")
|
||||||
|
# combined.show()
|
||||||
|
return f"{output_path}/{file_name}"
|
||||||
|
|
||||||
|
# If logo was off
|
||||||
|
# Save the image
|
||||||
|
img.save(f"{output_path}/{file_name}")
|
||||||
|
# combined.show()
|
||||||
|
return f"{output_path}/{file_name}"
|
||||||
120
sources/ChristianQuotes.txt
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
Don't worry about the future.
|
||||||
|
This is the day that the LORD has made.
|
||||||
|
Believe your prayers will be answered.
|
||||||
|
Everyday is a gift from God.
|
||||||
|
Where the Spirit of the Lord is, there is freedom.
|
||||||
|
When you stress it, pray about it.
|
||||||
|
Thank you God for another day.
|
||||||
|
At the right time, I, the Lord, will make it happen.
|
||||||
|
God says you are more than a conqueror.
|
||||||
|
Go to God first.
|
||||||
|
I can do all things through Him who strengthens me.
|
||||||
|
God's word never fails.
|
||||||
|
God is greater than your fears.
|
||||||
|
God is greater than the highs and lows.
|
||||||
|
He is risen.
|
||||||
|
God's ways > my ways
|
||||||
|
No prayer is too small for God.
|
||||||
|
I am not lucky, I am blessed.
|
||||||
|
I will refresh the weary and satisfy the faint.
|
||||||
|
Jesus loves you on your bad days too.
|
||||||
|
With God all things are possible.
|
||||||
|
Put your trust in the one who holds it all.
|
||||||
|
Keep God first.
|
||||||
|
God, thank you.
|
||||||
|
God is always on time.
|
||||||
|
God heard you. Be patient.
|
||||||
|
Thank God before it happens.
|
||||||
|
God will never let you down.
|
||||||
|
Jesus heals.
|
||||||
|
God is patient with you.
|
||||||
|
I will strengthen you and help you.
|
||||||
|
God makes no mistakes.
|
||||||
|
Love never fails.
|
||||||
|
I have hidden your word in my heart.
|
||||||
|
Always be joyful. Never stop praying.
|
||||||
|
Don't worry about the future.
|
||||||
|
Less on me, more of him.
|
||||||
|
Focus on God.
|
||||||
|
God has a plan.
|
||||||
|
God is with you.
|
||||||
|
Jesus changes everything.
|
||||||
|
My future is in God's hands.
|
||||||
|
God is for you.
|
||||||
|
Lord, guide me in every situation.
|
||||||
|
God is fighting for you.
|
||||||
|
Don't forget to pray today.
|
||||||
|
Pray in the good times too.
|
||||||
|
Every word of God proves true.
|
||||||
|
God so loved.
|
||||||
|
Be anxious for nothing.
|
||||||
|
One prayer can do a lot.
|
||||||
|
Lord, guide me.
|
||||||
|
Abide in Him.
|
||||||
|
God's plan is worthy waiting for.
|
||||||
|
Choose worship over worry.
|
||||||
|
God is always with you.
|
||||||
|
God's plan, not mine.
|
||||||
|
Prayer is a relationship with God.
|
||||||
|
When you wake up, pray.
|
||||||
|
Give it to God.
|
||||||
|
Jesus is the permanent fix to our problems.
|
||||||
|
God is able.
|
||||||
|
You have to let God handle it.
|
||||||
|
God listens when you pray.
|
||||||
|
Never get tired of doing good.
|
||||||
|
When everything else fails. God doesn't.
|
||||||
|
Set you minds on things above.
|
||||||
|
God keeps his promises.
|
||||||
|
You are never too lost to be found.
|
||||||
|
In His presence there is fullness of joy.
|
||||||
|
Let my life be an example.
|
||||||
|
Love casts out fear.
|
||||||
|
The LORD confides in those who fear him.
|
||||||
|
Quit overthinking and just pray.
|
||||||
|
Give God your weakness and He will give you His strength.
|
||||||
|
In him you have peace.
|
||||||
|
Trust God when he tells you to wait.
|
||||||
|
God knows everything and still he listens.
|
||||||
|
Jesus, I am all in.
|
||||||
|
God has a purpose for your life.
|
||||||
|
He turns my darkness into light.
|
||||||
|
The joy of the Lord is my strength.
|
||||||
|
God, I pray that I would draw closer to you.
|
||||||
|
Your comfort broughts joy to my soul.
|
||||||
|
God loves you unconditionally.
|
||||||
|
God hears your prayer. Trust him timing.
|
||||||
|
In you, LORD my God, I put my trust.
|
||||||
|
For no word from God will every fail.
|
||||||
|
Worry doesn't change anything. Prayer does.
|
||||||
|
Faith, Hope, Love.
|
||||||
|
Keep praying as you wait.
|
||||||
|
Reminder: God forgave you.
|
||||||
|
God has given you a spirit of power, of love and of a sound mind.
|
||||||
|
God has not given us a spirit of fear.
|
||||||
|
You are my defender, my place of safety in times of troubles.
|
||||||
|
We love because He first loved us.
|
||||||
|
Even when you are frustrated, seek God.
|
||||||
|
God is faithful.
|
||||||
|
God is all we need.
|
||||||
|
Lord, I can't do this on my own.
|
||||||
|
Walk by faith, not by sight.
|
||||||
|
Being a Christian doesn't change what you deal with. It changes how you deal with it.
|
||||||
|
In my weakness, you give me strength.
|
||||||
|
I will refresh the weary and satisfy the faint.
|
||||||
|
Anxiety comes from the world, peace comes from God.
|
||||||
|
If God's for you, It doesn't matter what's against you.
|
||||||
|
The Way, The Truth, The Life
|
||||||
|
God is most glorified in us when we are most satisfied in Him.
|
||||||
|
True faith means putting every hope in God's fidelity to His Promises.
|
||||||
|
Faith does not eliminate questions. But faith knows where to take them.
|
||||||
|
Some of God's greatest gifts are unanswered prayers.
|
||||||
|
What God intended for you goes far beyond anything you can imagine.
|
||||||
|
Life is God's novel. Let him write it.
|
||||||
|
Your word is a lamp to my feet and a light for my path.
|
||||||
|
Let us rejoice and be glad in the Lord.
|
||||||
|
Fear ends where faith begins.
|
||||||
|
God is my first priority.
|
||||||
|
Amazing grace.
|
||||||
|
What would Jesus do?
|
||||||
|
My lifeguard walked on water.
|
||||||
BIN
sources/images/autumn-111315_1920.jpg
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
sources/images/cropped/autumn-111315_1920.jpg
Normal file
|
After Width: | Height: | Size: 306 KiB |
BIN
sources/images/cropped/darken/autumn-111315_1920.jpg
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
sources/logo.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
sources/logo.psd
Normal file
117
verse_handler.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import os
|
||||||
|
from string import ascii_letters
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
|
||||||
|
def create_image(text, font_path, font_size, max_char_count, image_size, save_path, text_source):
|
||||||
|
save_path += "/verse_images"
|
||||||
|
text = fix_fonts(text, font_path)
|
||||||
|
# Open a blank image
|
||||||
|
img = Image.new('RGBA', image_size, color=(190, 190, 190, 0))
|
||||||
|
|
||||||
|
# Load selected font
|
||||||
|
font = ImageFont.truetype(font=f'{font_path}', size=font_size)
|
||||||
|
|
||||||
|
# Create DrawText object
|
||||||
|
draw = ImageDraw.Draw(im=img)
|
||||||
|
|
||||||
|
# Define our text:
|
||||||
|
# Calculate the average length of a single character of our font.
|
||||||
|
# Note: this takes into account the specific font and font size.
|
||||||
|
avg_char_width = sum(font.getsize(char)[0] for char in ascii_letters) / len(ascii_letters)
|
||||||
|
|
||||||
|
# Translate this average length into a character count
|
||||||
|
max_char_count = max(int(img.size[0] * .718 / avg_char_width), max_char_count)
|
||||||
|
|
||||||
|
# Create a wrapped text object using scaled character count
|
||||||
|
new_text = textwrap.fill(text=text, width=max_char_count)
|
||||||
|
|
||||||
|
# Draw the shadow text
|
||||||
|
shadow_image = Image.new('RGBA', img.size, color=(255, 255, 255, 0))
|
||||||
|
shadow_draw = ImageDraw.Draw(im=shadow_image)
|
||||||
|
shadow_draw.text(xy=(img.size[0] / 2 - 1, img.size[1] / 2 + 4), text=new_text, font=font, fill=(0, 0, 0, 80), anchor='mm',
|
||||||
|
align='center')
|
||||||
|
# Add main text to the image
|
||||||
|
draw.text(xy=(img.size[0] / 2, img.size[1] / 2), text=new_text, font=font, fill=(255, 255, 255, 255), anchor='mm',
|
||||||
|
align='center')
|
||||||
|
# combine shadow and main
|
||||||
|
combined = Image.alpha_composite(shadow_image, img)
|
||||||
|
|
||||||
|
# check if image of this source (bible reference) exists already
|
||||||
|
path_to_check = f"{save_path}/{text_source}.png"
|
||||||
|
i = 1
|
||||||
|
while os.path.exists(path_to_check):
|
||||||
|
path_to_check = f"{save_path}/{text_source}-{i}.png"
|
||||||
|
i += 1
|
||||||
|
# Save the image
|
||||||
|
combined.save(f"{path_to_check}")
|
||||||
|
# combined.show()
|
||||||
|
return f"{path_to_check}"
|
||||||
|
|
||||||
|
|
||||||
|
def create_post_images(video_path: str, verse_image_path, text_source, output_folder):
|
||||||
|
# Open the video file
|
||||||
|
video = cv2.VideoCapture(video_path)
|
||||||
|
|
||||||
|
# Get the frame rate of the video
|
||||||
|
fps = int(video.get(cv2.CAP_PROP_FPS))
|
||||||
|
|
||||||
|
# Set the time in seconds to extract a frame from
|
||||||
|
time_in_seconds = 2
|
||||||
|
|
||||||
|
# Calculate the frame index to extract
|
||||||
|
frame_index = time_in_seconds * fps
|
||||||
|
|
||||||
|
# Set the output image size
|
||||||
|
output_size = (1080, 1080)
|
||||||
|
|
||||||
|
# Loop through the video frames until we reach the desired frame
|
||||||
|
for i in range(frame_index):
|
||||||
|
ret, frame = video.read()
|
||||||
|
|
||||||
|
# Crop the middle square of the frame
|
||||||
|
height, width, channels = frame.shape
|
||||||
|
y = int((height - width) / 2)
|
||||||
|
cropped_frame = frame[y:y+1080, 0:width]
|
||||||
|
|
||||||
|
background = Image.fromarray(cropped_frame)
|
||||||
|
verse = Image.open(verse_image_path)
|
||||||
|
|
||||||
|
combined = Image.blend(background, verse, 1)
|
||||||
|
|
||||||
|
# Create a drawing object
|
||||||
|
draw = ImageDraw.Draw(combined)
|
||||||
|
|
||||||
|
# Define the text to add and the font to use
|
||||||
|
text = 'Hello, World!'
|
||||||
|
font = ImageFont.truetype(r"C\:/Users/Samurai/AppData/Local/Microsoft/Windows/Fonts/Aloevera-OVoWO.ttf", size=36)
|
||||||
|
|
||||||
|
# Determine the position to place the text
|
||||||
|
text_width, text_height = draw.textsize(text, font=font)
|
||||||
|
x = (combined.width - text_width) / 2
|
||||||
|
y = 1300
|
||||||
|
|
||||||
|
# Add the text to the image
|
||||||
|
draw.text((x, y), text, font=font, fill=(255, 255, 255))
|
||||||
|
|
||||||
|
output_name = video_path.split('/')
|
||||||
|
output_name = output_name[len(output_name) - 1].strip(".mp4")
|
||||||
|
combined.save(f"{output_folder}/post_images/{output_name}.jpg")
|
||||||
|
|
||||||
|
# Save the frame as an image
|
||||||
|
# output_name = video_path.split('/')
|
||||||
|
# output_name = output_name[len(output_name) - 1].strip(".mp4")
|
||||||
|
# cv2.imwrite(f"{output_folder}/post_images/{output_name}.jpg", cropped_frame)
|
||||||
|
#
|
||||||
|
# Release the video file
|
||||||
|
video.release()
|
||||||
|
|
||||||
|
|
||||||
|
def fix_fonts(text, font):
|
||||||
|
# Font 6 can't display '
|
||||||
|
if (font.__contains__("FlowersSunday")):
|
||||||
|
return text.replace("'", "")
|
||||||
|
return text
|
||||||