From 204ff8335d0585d861bbf1173e89df8bd30fef24 Mon Sep 17 00:00:00 2001 From: ggeerraarrdd Date: Fri, 17 Nov 2023 00:26:44 -0600 Subject: [PATCH] Add OUTPUT_MOBILES --- .gitignore | 1 + README.md | 14 +-- helpers.py | 1 + local_settings.py | 17 +++- output_mobiles.py | 226 ++++++++++++++++++++++++++++++++++++++++++++++ portfoliofy.py | 56 ++++++------ 6 files changed, 276 insertions(+), 39 deletions(-) create mode 100644 output_mobiles.py diff --git a/.gitignore b/.gitignore index 2040a0f..2c63d3b 100644 --- a/.gitignore +++ b/.gitignore @@ -169,4 +169,5 @@ cython_debug/ flask_session/ /*_session/ +output_full.py #################################################### diff --git a/README.md b/README.md index 373947a..d890fe5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Assemble screenshots of web projects for your portfolio Once a web project is done, it's time to document your hard work and show it off. _Portfoliofy_ makes that process easier by doing all the screenshots for you and assembling them together into portfolio-ready files. -As of v2.1.0, the following `OUTPUT_` types can be generated: +As of v2.2.0, the following `OUTPUT_` types can be generated: * `OUTPUT_SCREENSHOTS` * Four image files of screenshots taken in different window sizes mimicking the viewport of a desktop (2160x1360), a laptop (1440x900), a tablet (768x1024) and a smartphone (230x490). @@ -14,6 +14,8 @@ As of v2.1.0, the following `OUTPUT_` types can be generated: * An image file of those screenshots overlaid on top schematic diagrams and then collaged together. (See below for an example ouput.) * `OUTPUT_BROWSER` * An image file of the desktop screenshot overlaid on top of a schematic diagram. (Scroll to the bottom for an example ouput.) +* `OUTPUT_MOBILES` + * An image file of the tablet and smartphone screenshots overlaid on top of a schematic diagram and paired together. (Scroll to the bottom for an example ouput.) More coming soon! @@ -56,11 +58,11 @@ The output files are stored in a subdirectory of the `output` directory. This is a list of parameters you can change in `local_settings.py`. -| Parameter | Type | Default value | Value range | Description | -| ----------------- | ------ | ---------------------- | ------------ | ----------- | -| url | string | 'https://www.nps.gov/' | '' | The URL to portfoliofy. | -| wait | int | 2 | 0-60 | Time in seconds to allow URL to load before taking screenshot. | -| screenshots | bool | True | True, False | If TRUE, all screenshots are saved. | +| Parameter | Type | Default value | Value range | Description | +| ----------------- | ------ | ------------------------ | ------------ | ----------- | +| url | string | '' | '' | The URL to portfoliofy. | +| wait | int | 2 | 0-60 | Time in seconds to allow URL to load before taking screenshot. | +| screenshots | bool | True | True, False | If TRUE, all screenshots are saved. | `OUTPUT_MAIN` and `OUTPUT_BROWSER` are generated by default but you can change this default behavior by editing the value of `request` in their respective dict in `user_input`. Other customizations can be set. diff --git a/helpers.py b/helpers.py index 04e9668..10e701a 100644 --- a/helpers.py +++ b/helpers.py @@ -13,6 +13,7 @@ def get_screenshot(remote_url, wait, directory_path, input): options.add_argument(f"--window-size={input['width_large']},{input['height_large']}") options.add_argument(f"--no-sandbox") options.add_argument(f"--headless") + options.add_argument(f"--hide-scrollbars") # Open Chrome webdriver driver = webdriver.Chrome(options=options) diff --git a/local_settings.py b/local_settings.py index 14d99b3..3360560 100644 --- a/local_settings.py +++ b/local_settings.py @@ -20,6 +20,15 @@ "base_stroke_color": "#23445D", "base_fill_color": "#BAC8D3", }, + "output_mobiles": { + "request": True, + "format": "png", + "doc_pad_h": 300, + "doc_pad_v": 200, + "doc_fill_color": "#FFFFFF", + "base_stroke_color": "#23445D", + "base_fill_color": "#BAC8D3", + }, } @@ -60,9 +69,9 @@ "width_large": 768, "height_large": 1024, "filename_medium": "screenshot_tablet_medium.png", - "width_medium": None, + "width_medium": 1016, "height_medium": None, - "medium_height_crop": None, + "medium_height_crop": 1336, "filename_small": "screenshot_tablet_small.png", "width_small": 600, "height_small": None, @@ -73,9 +82,9 @@ "width_large": 430, "height_large": 932, "filename_medium": "screenshot_smartphone_medium.png", - "width_medium": None, + "width_medium": 360, "height_medium": None, - "medium_height_crop": None, + "medium_height_crop": 760, "filename_small": "screenshot_smartphone_small.png", "width_small": 230, "height_small": None, diff --git a/output_mobiles.py b/output_mobiles.py new file mode 100644 index 0000000..74bed32 --- /dev/null +++ b/output_mobiles.py @@ -0,0 +1,226 @@ +from PIL import Image, ImageDraw, ImageOps +from cairosvg import svg2png +from textwrap import dedent +from helpers import get_screenshot_resized, get_screenshot_resized_overlaid, get_output_padded, cleanup + + +def process_request_mobiles(blueprint_user, blueprint_system, directory_main, directory_screenshots): + + tablet = blueprint_system.get("tablet") + smartphone = blueprint_system.get("smartphone") + + # ################################################## # + # Handle OUTPUT_MOBILES - tablet + # ################################################## # + + # Set svg for tablet + svg_tablet = dedent(dedent(dedent(f'''\ + + + + + + + + + ''' + ))) + + # Create base - tablet + filename_output_mobiles_tablet_base_svg = "output_mobiles_tablet_base.svg" + filename_output_mobiles_tablet_base_png = "output_mobiles_tablet_base.png" + get_output_mobiles_base(blueprint_user, directory_main, svg_tablet, filename_output_mobiles_tablet_base_svg, filename_output_mobiles_tablet_base_png) + print("OUTPUT_MOBILES - tablet - base - generated.") + + # Create overlay - tablet - temp + filename_input = tablet["filename_large"] + filename_output_temp = filename_output_mobiles_tablet_overlay_temp_png = "output_mobiles_tablet_overlay_temp.png" + new_width = tablet["width_medium"] + height_crop = tablet["medium_height_crop"] + get_screenshot_resized(directory_main, directory_screenshots, filename_input, filename_output_temp, new_width, height_crop) + print("OUTPUT_MOBILES - tablet - overlay - generated.") + + # Create overlay - tablet - final + filename_output_final = filename_output_mobiles_tablet_overlay_final_png = "output_mobiles_tablet_overlay_final.png" + get_output_mobiles_overlay_temp(directory_main, filename_output_mobiles_tablet_overlay_temp_png, filename_output_final) + + # Combine base layer and overlay + base = f"{directory_main}/{filename_output_mobiles_tablet_base_png}" + overlay = f"{directory_main}/{filename_output_mobiles_tablet_overlay_final_png}" + lat = 34 + lng = 36 + filename_output_mobiles_tablet_final = "output_mobiles_tablet_final.png" + get_output_mobiles_overlay_final(base, overlay, lat, lng, directory_main, filename_output_mobiles_tablet_final) + print("OUTPUT_BROWSER - tablet - temp - generated.") + + + # ################################################## # + # Handle OUTPUT_MOBILES - smartphone + # ################################################## # + + # Set svg for smartphone + svg_smartphone = dedent(dedent(dedent(f'''\ + + + + + + + + + ''' + ))) + + # Create base - smartphone + filename_output_mobiles_smartphone_base_svg = "output_mobiles_smartphone_base.svg" + filename_output_mobiles_smartphone_base_png = "output_mobiles_smartphone_base.png" + get_output_mobiles_base(blueprint_user, directory_main, svg_smartphone, filename_output_mobiles_smartphone_base_svg, filename_output_mobiles_smartphone_base_png) + print("OUTPUT_MOBILES - smartphone - base - generated.") + + # Create overlay - smartphone - temp + filename_input = smartphone["filename_large"] + filename_output_temp = filename_output_mobiles_smartphone_overlay_temp_png = "output_mobiles_smartphone_overlay_temp.png" + new_width = smartphone["width_medium"] + height_crop = smartphone["medium_height_crop"] + get_screenshot_resized(directory_main, directory_screenshots, filename_input, filename_output_temp, new_width, height_crop) + print("OUTPUT_MOBILES - smartphone - overlay - generated.") + + # Create overlay - smartphone - final + filename_output_final = filename_output_mobiles_smartphone_overlay_final_png = "output_mobiles_smartphone_overlay_final.png" + get_output_mobiles_overlay_temp(directory_main, filename_output_mobiles_smartphone_overlay_temp_png, filename_output_final) + + # Combine base layer and overlay + base = f"{directory_main}/{filename_output_mobiles_smartphone_base_png}" + overlay = f"{directory_main}/{filename_output_mobiles_smartphone_overlay_final_png}" + lat = 22 + lng = 23 + filename_output_mobiles_smartphone_final = "output_mobiles_smartphone_final.png" + get_output_mobiles_overlay_final(base, overlay, lat, lng, directory_main, filename_output_mobiles_smartphone_final) + print("OUTPUT_BROWSER - smartphone - temp - generated.") + + + # ################################################## # + # Handle OUTPUT_MOBILES - all temp + # ################################################## # + + width = 1605 + height = 1406 + + output_mobiles_all_base = Image.new("RGB", (width, height), (255, 255, 255)) + + output_mobiles_tablet = Image.open(f"{directory_main}/{filename_output_mobiles_tablet_final}") + output_mobiles_smartphone = Image.open(f"{directory_main}/{filename_output_mobiles_smartphone_final}") + + output_mobiles_tablet_box = (520, 0) + output_mobiles_all_base.paste(output_mobiles_tablet, output_mobiles_tablet_box) + + output_mobiles_smartphone_box = (0, 600) + output_mobiles_all_base.paste(output_mobiles_smartphone, output_mobiles_smartphone_box) + + filename_output_mobiles_all_temp = "output_mobiles_all_temp.png" + output_mobiles_all_base.save(f"{directory_main}/{filename_output_mobiles_all_temp}") + + print("OUTPUT_MOBILES- all - temp - generated.") + + + # ################################################## # + # Handle OUTPUT_MOBILES - all final + # ################################################## # + + # Add padding + right = blueprint_user["doc_pad_h"] + left = blueprint_user["doc_pad_h"] + top = blueprint_user["doc_pad_v"] + bottom = blueprint_user["doc_pad_v"] + color = blueprint_user["doc_fill_color"] + filename_output_mobiles_final = "output_mobiles.png" + get_output_padded(directory_main, filename_output_mobiles_all_temp, filename_output_mobiles_final, right, left, top, bottom, color) + print("OUTPUT_MOBILES - final - generated.") + + + # ################################################## # + # Delete temp files + # ################################################## # + + cleanup(directory_main, filename_output_mobiles_tablet_base_svg) + cleanup(directory_main, filename_output_mobiles_tablet_base_png) + cleanup(directory_main, filename_output_mobiles_tablet_overlay_temp_png) + cleanup(directory_main, filename_output_mobiles_tablet_overlay_final_png) + + cleanup(directory_main, filename_output_mobiles_smartphone_base_svg) + cleanup(directory_main, filename_output_mobiles_smartphone_base_png) + cleanup(directory_main, filename_output_mobiles_smartphone_overlay_temp_png) + cleanup(directory_main, filename_output_mobiles_smartphone_overlay_final_png) + + cleanup(directory_main, filename_output_mobiles_tablet_final) + cleanup(directory_main, filename_output_mobiles_smartphone_final) + cleanup(directory_main, filename_output_mobiles_all_temp) + + return 1 + + +def get_output_mobiles_base(blueprint, directory_main, svg, svg_filename, png_filename): + + # Create SVG file + with open(f"{directory_main}/{svg_filename}", "w") as file: + file.write(svg) + + # Convert to SVG to PNG + svg2png(url=f"{directory_main}/{svg_filename}", write_to=f"{directory_main}/{png_filename}", background_color=blueprint["doc_fill_color"]) + + return 1 + + +def get_output_mobiles_overlay_temp(directory_path, filename_input, filename_output): + + # Open the image + image = Image.open(f"{directory_path}/{filename_input}") + + # Create a border with rounded corners + border_radius = 20.32 + border_width = 0 + border_color = (255, 0, 0) # Red color + + # Create a mask with rounded corners + mask = Image.new("L", image.size, 0) + mask_draw = ImageDraw.Draw(mask) + mask_draw.rounded_rectangle((0, 0, image.width, image.height), border_radius, fill=255) + + # Apply the mask to the image + image_with_border = ImageOps.fit(image, mask.size) + image_with_border.putalpha(mask) + + # Draw the border + border_draw = ImageDraw.Draw(image_with_border) + border_draw.rounded_rectangle((0, 0, image.width, image.height), border_radius, outline=border_color, width=border_width) + + image_with_border.save(f"{directory_path}/{filename_output}") + + return 1 + + +def get_output_mobiles_overlay_final(base, overlay, lat, lng, directory_main, filename_output): + + # Open the base image + base_image = Image.open(base) + + # Open the overlay image + overlay_image = Image.open(overlay) + + # Set coordinates of top-left corner + box = (lat, lng) + + # Overlay the images + base_image.paste(overlay_image, box, mask=overlay_image) + + # Save the final image + base_image.save(f"{directory_main}/{filename_output}") + + return 1 + \ No newline at end of file diff --git a/portfoliofy.py b/portfoliofy.py index 78c82c9..2ca684a 100644 --- a/portfoliofy.py +++ b/portfoliofy.py @@ -6,21 +6,20 @@ from helpers import get_screenshot from output_browser import process_request_browser from output_main import process_request_main +from output_mobiles import process_request_mobiles def main(): # ################################################## # - # # Validate parameters - # # ################################################## # - remote_url = user_input.get("url") wait = user_input.get("wait") screenshots = user_input.get("screenshots") output_main = user_input.get("output_main") output_browser = user_input.get("output_browser") + output_mobiles = user_input.get("output_mobiles") status_code = get_url(remote_url) @@ -33,9 +32,7 @@ def main(): print("Valid parameters.") # ################################################## # - # # Create directories - # # ################################################## # now = datetime.now() directory = now.strftime('%y%m%d_%H%M%S_%f')[:-3] @@ -45,13 +42,9 @@ def main(): directory_screenshots = f"{directory_main}/screenshots" os.makedirs(directory_screenshots) - # ################################################## # - # - # Get screenshots - # + # Create screenshots # ################################################## # - desktop = system_input.get("desktop") laptop = system_input.get("laptop") tablet = system_input.get("tablet") @@ -62,49 +55,54 @@ def main(): print(get_screenshot(remote_url, wait, directory_screenshots, tablet)) print(get_screenshot(remote_url, wait, directory_screenshots, smartphone)) - # ################################################## # - # - # Process Output Request - MAIN - # + # Process Request - OUTPUT_MAIN # ################################################## # - if output_main["request"] == True: - result = process_request_main(output_main, system_input, directory_main, directory_screenshots) + result = process_request_main( + output_main, system_input, directory_main, directory_screenshots) if result == 1: print("OUTPUT_MAIN request processed.") - + else: print("OUTPUT_MAIN not requested.") - # ################################################## # - # - # Process Output Request - BROWSER - # + # Process Request - OUPUT_BROWSER # ################################################## # - if output_browser["request"] == True: - result = process_request_browser(output_browser, desktop, directory_main, directory_screenshots) + result = process_request_browser( + output_browser, desktop, directory_main, directory_screenshots) if result == 1: print("OUTPUT_BROWSER request processed.") - + else: print("OUTPUT_BROWSER not requested.") - # ################################################## # - # - # Process Output Request - SCREENSHOTS - # + # Process Request - OUPUT_MOBILES # ################################################## # + if output_mobiles["request"] == True: + result = process_request_mobiles( + output_mobiles, system_input, directory_main, directory_screenshots) + + if result == 1: + print("OUTPUT_MOBILES request processed.") + + else: + + print("OUTPUT_MOBILES not requested.") + + # ################################################## # + # Process Request - OUPUT_SCREENSHOTS + # ################################################## # if screenshots == False: shutil.rmtree(directory_screenshots) @@ -119,7 +117,7 @@ def get_url(url): return int(response.status_code) else: return 0 - + except: return 0