diff --git a/Meme_Generator/MemeEngine/MemeEngine.py b/Meme_Generator/MemeEngine/MemeEngine.py index b1ad530..aa790d2 100644 --- a/Meme_Generator/MemeEngine/MemeEngine.py +++ b/Meme_Generator/MemeEngine/MemeEngine.py @@ -11,24 +11,33 @@ class MemeEngine: """Initialize meme engine with path to save generated memes.""" self.output_path = output_path + def resize_image(self, img, width=500): + """Resize image to specified width while maintaining aspect ratio.""" + if img.size[0] > width: + ratio = width / (img.size[0] * 1.0) + height = ratio * img.size[1] + img = img.resize((int(width), int(height)), Image.NEAREST) + return img + + def draw_text(self, image, message): + """Draw text on the image.""" + draw = ImageDraw.Draw(image) + font = ImageFont.truetype( + "./_data/font/calibri_regular.ttf", int(image.size[1] / 20) + ) + draw.text((20, 20), message, font=font, fill="white") + return image + def make_meme(self, img_path, text, author, width=500) -> str: """Generate a meme image with given text and author.""" - output_file = f"{self.output_path}/{random.randint(0,10000)}.jpg" + output_file = f"{self.output_path}/{random.randint(0, 10000)}.jpg" message = f"{text}\n- {author}" try: with Image.open(img_path) as img: - # Resize image while maintaining aspect ratio - width = 500 if img.size[0] > 500 else img.size[0] - ratio = width / (img.size[0] * 1.0) - height = ratio * img.size[1] - img = img.resize((int(width), int(height)), Image.NEAREST) - draw = ImageDraw.Draw(img) - font = ImageFont.truetype( - "./_data/font/calibri_regular.ttf", int(height / 20) - ) - draw.text((20, 20), message, font=font, fill="white") - img.save(output_file) + image_resize = self.resize_image(img, width=width) + image_draw = self.draw_text(image_resize, message) + image_draw.save(output_file) except Exception as err: print(f"Error: {err}") diff --git a/Meme_Generator/MemeEngine/__init__.py b/Meme_Generator/MemeEngine/__init__.py index 1846263..37ccfb3 100644 --- a/Meme_Generator/MemeEngine/__init__.py +++ b/Meme_Generator/MemeEngine/__init__.py @@ -1 +1,6 @@ +"""MemeEngine package. + +Provides the MemeEngine class for generating meme images from templates. +""" + from .MemeEngine import MemeEngine diff --git a/Meme_Generator/QuoteEngine/IngestorInterface.py b/Meme_Generator/QuoteEngine/IngestorInterface.py index 4367a6b..b182ca3 100644 --- a/Meme_Generator/QuoteEngine/IngestorInterface.py +++ b/Meme_Generator/QuoteEngine/IngestorInterface.py @@ -19,5 +19,6 @@ class IngestorInterface(ABC): @classmethod @abstractmethod def parse(cls, path: str) -> List[QuoteModel]: - """Abstract method to parse the file and return a list of QuoteModel objects.""" + """Abstract method to parse the file and return a list of QuoteModel + objects.""" pass diff --git a/Meme_Generator/QuoteEngine/PDFIngestor.py b/Meme_Generator/QuoteEngine/PDFIngestor.py index 317d703..b068f8a 100644 --- a/Meme_Generator/QuoteEngine/PDFIngestor.py +++ b/Meme_Generator/QuoteEngine/PDFIngestor.py @@ -23,7 +23,7 @@ class PDFIngestor(IngestorInterface): tmp = f"./tmp/{random.randint(0, 10000)}.txt" try: # pdftotext - call = subprocess.call(["pdftotext", path, tmp]) + subprocess.call(["pdftotext", path, tmp]) with open(tmp, "r") as file: lines = file.readlines() except FileNotFoundError as err: diff --git a/Meme_Generator/QuoteEngine/QuoteModel.py b/Meme_Generator/QuoteEngine/QuoteModel.py index 409881a..c34927d 100644 --- a/Meme_Generator/QuoteEngine/QuoteModel.py +++ b/Meme_Generator/QuoteEngine/QuoteModel.py @@ -10,5 +10,5 @@ class QuoteModel: self.author = author def __repr__(self): - """String representation of the QuoteModel object.""" + """Return a string representation of the QuoteModel.""" return f"{self.body} - {self.author}" diff --git a/Meme_Generator/QuoteEngine/__init__.py b/Meme_Generator/QuoteEngine/__init__.py index bd01df2..ce3c5be 100644 --- a/Meme_Generator/QuoteEngine/__init__.py +++ b/Meme_Generator/QuoteEngine/__init__.py @@ -1,3 +1,8 @@ +"""QuoteEngine package. + +Provides tools for parsing and representing quote data. +""" + from .IngestorInterface import IngestorInterface from .CSVIngestor import CSVIngestor from .DocxIngestor import DocxIngestor diff --git a/Meme_Generator/README.md b/Meme_Generator/README.md index 4875191..cbf90fa 100644 --- a/Meme_Generator/README.md +++ b/Meme_Generator/README.md @@ -36,4 +36,17 @@ Open link `http://127.0.0.1:5000` in web browser `CSVIngestor`: Module for ingesting CSV files containing quotes. \ `DocxIngestor`: Module for ingesting Docx files containing quotes. \ `TextIngestor`: Module for ingesting text files containing quotes. \ -`PDFIngestor`: Module for ingesting PDF files containing quotes. \ No newline at end of file +`PDFIngestor`: Module for ingesting PDF files containing quotes. + +### Format checking +```sh +$ pip install docformatter +$ pip install autopep8 +$ pip install black +$ pip install flake8 + +$ docformatter -i -r --wrap-summaries 79 --wrap-descriptions 79 . +$ autopep8 --in-place --recursive --aggressive . +$ black . +$ flake8 . +``` \ No newline at end of file diff --git a/Meme_Generator/app.py b/Meme_Generator/app.py index 7e44397..06cea49 100644 --- a/Meme_Generator/app.py +++ b/Meme_Generator/app.py @@ -1,3 +1,5 @@ +"""Flask app to generate memes.""" + import random import os import requests @@ -6,17 +8,17 @@ from flask import Flask, render_template, abort, request from QuoteEngine import Ingestor from MemeEngine import MemeEngine -# Create the Flask application object. "__name__" tells Flask where to find templates and static files. +# Create the Flask application object. "__name__" tells Flask, +# where to find templates and static files. app = Flask(__name__) -# Create a global MemeEngine instance that will write generated memes into "./static" -# so that the images can be served by the web server. +# Create a global MemeEngine instance that will write generated memes +# into "./static" so that the images can be served by the web server. meme = MemeEngine("./static") def setup(): - """Load all resources""" - + """Load all resources.""" quote_files = [ "./_data/DogQuotes/DogQuotesTXT.txt", "./_data/DogQuotes/DogQuotesDOCX.docx", @@ -45,7 +47,7 @@ quotes, imgs = setup() @app.route("/") def meme_rand(): - """Generate a random meme + """Generate a random meme. Steps: - Pick a random image from imgs @@ -63,7 +65,7 @@ def meme_rand(): @app.route("/create", methods=["GET"]) def meme_form(): - """User input for meme information + """User input for meme information. This route renders a form where the user can input: - image_url: URL of the source image @@ -75,7 +77,7 @@ def meme_form(): @app.route("/create", methods=["POST"]) def meme_post(): - """Create a user defined meme + """Create a user defined meme. This route: - Reads form data sent via POST from the meme_form page @@ -95,8 +97,8 @@ def meme_post(): tmp_file = f"tmp/{random.randint(0, 10000)}.jpg" with open(tmp_file, "wb") as file: file.write(image.content) - except: - print("Failed to generate meme") + except OSError as e: + print("Failed to generate meme:", e) path = None if os.path.exists(tmp_file): os.remove(tmp_file) diff --git a/Meme_Generator/meme.py b/Meme_Generator/meme.py index 3163595..d048fae 100644 --- a/Meme_Generator/meme.py +++ b/Meme_Generator/meme.py @@ -1,3 +1,5 @@ +"""Generate a meme from an image and a quote.""" + import os import random import argparse @@ -6,7 +8,7 @@ from QuoteEngine import QuoteModel, Ingestor def generate_meme(path=None, body=None, author=None): - """Generate a meme given an path and a quote""" + """Generate a meme given an path and a quote.""" img = None quote = None @@ -45,7 +47,8 @@ def generate_meme(path=None, body=None, author=None): if __name__ == "__main__": - """Add path, quote, and author arguments for CLI, then print meme generation.""" + """Add path, quote, and author arguments for CLI, then print meme + generation.""" parser = argparse.ArgumentParser(description="Meme Generator") parser.add_argument("--path", type=str, help="Image path") parser.add_argument("--body", type=str, help="Quote adding to meme")