Skip to content

Commit

Permalink
Add OUTPUT_FULL
Browse files Browse the repository at this point in the history
  • Loading branch information
ggeerraarrdd committed Nov 20, 2023
1 parent 04b0a07 commit 4e2d03f
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,5 @@ cython_debug/
flask_session/
/*_session/

output_full.py
sketch*.py
####################################################
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ Once a web project is done, it's time to document your hard work and show it off
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).
* 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). And one image file of a full-page screenshot.
* `OUTPUT_MAIN`
* 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.)
* `OUTPUT_FULL`
* An image file of the full-pge screenshots overlaid on top of a schematic diagram. (Scroll to the bottom for an example ouput.)

More coming soon!

Expand Down Expand Up @@ -78,7 +80,7 @@ This is a list of parameters you can change in `local_settings.py`.

### Example

This code will portfoliofy a webpage served on a web server running on a local computer. It only requests `OUTPUT_BROWSER` in the default PNG format. `OUTPUT_MAIN` and `OUTPUT_MOBILES` will not be processed. But all `OUTPUT_SCREENSHOTS` will be saved. All other parameters remain set to their default values.
This code will portfoliofy a webpage served on a web server running on a local computer. It only requests `OUTPUT_BROWSER` in the default PNG format. `OUTPUT_MAIN`, `OUTPUT_MOBILES` and `OUTPUT_FULL` will not be processed. But all `OUTPUT_SCREENSHOTS` will be saved. All other parameters remain set to their default values.

```python
user_input = {
Expand Down Expand Up @@ -112,6 +114,15 @@ user_input = {
"base_stroke_color": "#23445D",
"base_fill_color": "#BAC8D3",
},
"output_full": {
"request": False,
"format": "png",
"doc_pad_h": 300,
"doc_pad_v": 200,
"doc_fill_color": "#FFFFFF",
"base_stroke_color": "#23445D",
"base_fill_color": "#BAC8D3",
},
}
```

Expand Down Expand Up @@ -150,3 +161,5 @@ New features development is ongoing.
![Portfoliofy](/images/portfoliofy2.png)

![Portfoliofy](/images/portfoliofy3.png)

![Portfoliofy](/images/portfoliofy4.png)
69 changes: 67 additions & 2 deletions helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import os
import json
import base64
from selenium import webdriver
from PIL import Image
from time import sleep
Expand Down Expand Up @@ -26,7 +28,70 @@ def get_screenshot(remote_url, wait, directory_path, input):
# Take screenshot
driver.close()

return f"{input['filename_large']} screenshot generated."
return 1


def get_screenshot_full(remote_url, wait, directory_path, input):

options = Options()
options.add_argument(f"--no-sandbox")
options.add_argument(f"--headless=new")
options.add_argument(f"--hide-scrollbars")

driver = webdriver.Chrome(options=options)

driver.get(remote_url)

sleep(wait)

filename_output_full_screenshot_png = input["filename_large"]

png = get_screenshot_full_chrome(driver)
with open(f"{directory_path}/{filename_output_full_screenshot_png}", 'wb') as f:
f.write(png)

driver.close()

return 1


def get_screenshot_full_chrome(driver) :

# Function adapted from StackOverflow answer
# https://stackoverflow.com/questions/45199076/take-full-page-screenshot-in-chrome-with-selenium/45201692#45201692

def send(cmd, params):
resource = "/session/%s/chromium/send_command_and_get_result" % \
driver.session_id
url = driver.command_executor._url + resource
body = json.dumps({'cmd':cmd, 'params': params})
response = driver.command_executor._request('POST', url, body)
return response.get('value')

def evaluate(script):
response = send('Runtime.evaluate', {
'returnByValue': True,
'expression': script
})
return response['result']['value']

metrics = evaluate( \
"({" + \
"width: Math.max(window.innerWidth, document.body.scrollWidth, " + \
"document.documentElement.scrollWidth)|0," + \
"height: Math.max(innerHeight, document.body.scrollHeight, " + \
"document.documentElement.scrollHeight)|0," + \
"deviceScaleFactor: window.devicePixelRatio || 1," + \
"mobile: typeof window.orientation !== 'undefined'" + \
"})")
send('Emulation.setDeviceMetricsOverride', metrics)
screenshot = send('Page.captureScreenshot', {
'format': 'png',
'fromSurface': True
})
send('Emulation.clearDeviceMetricsOverride', {})

return base64.b64decode(screenshot['data'])


def get_screenshot_resized(directory_main, directory_screenshots, filename_input, filename_output, new_width, height_crop):
Expand All @@ -51,7 +116,7 @@ def get_screenshot_resized(directory_main, directory_screenshots, filename_input
# Save the cropped image
cropped_image.save(f"{directory_main}/{filename_output}")

return f"{filename_output} screenshot generated."
return 1


def get_screenshot_resized_overlaid(base, overlay, lat, lng, directory_path, new_file_name):
Expand Down
Binary file modified images/portfoliofy1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/portfoliofy2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/portfoliofy3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/portfoliofy4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions local_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
"base_stroke_color": "#23445D",
"base_fill_color": "#BAC8D3",
},
"output_full": {
"request": True,
"format": "png",
"doc_pad_h": 300,
"doc_pad_v": 200,
"doc_fill_color": "#FFFFFF",
"base_stroke_color": "#23445D",
"base_fill_color": "#BAC8D3",
},
}


Expand Down Expand Up @@ -90,4 +99,17 @@
"height_small": None,
"small_height_crop": 490,
},
"full": {
"filename_large": "screenshot_full_large.png",
"width_large": 2160,
"height_large": 1360,
"filename_medium": "screenshot_full_medium.png",
"width_medium": 2048,
"height_medium": None,
"medium_height_crop": 1152,
"filename_small": "screenshot_full_small.png",
"width_small": 768,
"height_small": None,
"small_height_crop": 1024,
},
}
116 changes: 116 additions & 0 deletions output_full.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from PIL import Image, ImageOps
from cairosvg import svg2png
from textwrap import dedent
from helpers import get_output_padded, cleanup


def process_request_full(blueprint_user, blueprint_system, directory_main, directory_screenshots):

full = blueprint_system.get("full")

# Set svg for tablet
svg_full = dedent(dedent(dedent(f'''\
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="776px"
height="121px" viewBox="-0.5 -0.5 776 121" style="background-color: rgb(255, 255, 255);">
<defs />
<g>
<rect x="2" y="2" width="772" height="117" rx="17.55" ry="17.55" fill="#bac8d3" stroke="#23445d"
stroke-width="4" pointer-events="all" />
<ellipse cx="41" cy="31" rx="9" ry="9" fill="#ffffff" stroke="#23445d" stroke-width="2" pointer-events="all" />
<ellipse cx="73" cy="31" rx="9" ry="9" fill="#ffffff" stroke="#23445d" stroke-width="2" pointer-events="all" />
<ellipse cx="105" cy="31" rx="9" ry="9" fill="#ffffff" stroke="#23445d" stroke-width="2" pointer-events="all" />
</g>
</svg>'''
)))

# Create base - full
filename_output_full_base_svg = "output_full_base.svg"
filename_output_full_base_png = "output_full_base.png"
get_output_mobiles_base(blueprint_user, directory_main, svg_full, filename_output_full_base_svg, filename_output_full_base_png)

# Create overlay - full - temp
filename_input = blueprint_system["filename_large"]
filename_output = filename_output_full_overlay_png = "output_full_overlay.png"
get_output_full_overlay_resized(blueprint_system, directory_main, directory_screenshots, filename_input, filename_output)
get_output_full_overlay_bordered(blueprint_user, directory_main, filename_output)
print("OUTPUT_FULL - overlay - generated.")

output_full_base = Image.open(f"{directory_main}/{filename_output_full_base_png}")
output_full_overlay = Image.open(f"{directory_main}/{filename_output_full_overlay_png}")

width = 776
height = output_full_overlay.height + 60

output_full_final = Image.new("RGB", (width, height), (255, 255, 255))

output_full_final.paste(output_full_base, (0,0))
output_full_final.paste(output_full_overlay, (0,60))

filename_output_full_temp = "output_full_temp.png"
output_full_final.save(f"{directory_main}/{filename_output_full_temp}")

# 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_browser_final = "output_full_final.png"
get_output_padded(directory_main, filename_output_full_temp, filename_output_browser_final, right, left, top, bottom, color)
print("OUTPUT_FULL - final - generated.")

# Delete temp files
cleanup(directory_main, filename_output_full_base_svg)
cleanup(directory_main, filename_output_full_base_png)
cleanup(directory_main, filename_output_full_overlay_png)
cleanup(directory_main, filename_output_full_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_full_overlay_resized(blueprint, directory_main, directory_screenshots, filename_input, filename_output):

image = Image.open(f"{directory_screenshots}/{filename_input}")

aspect_ratio = image.height / image.width

new_height = int(blueprint["width_small"] * aspect_ratio)

# Resize the image
resized_image = image.resize((blueprint["width_small"], new_height))

resized_image.save(f"{directory_main}/{filename_output}")

return 1


def get_output_full_overlay_bordered(blueprint, directory_main, filename_input):

# Open the PNG image
image = Image.open(f"{directory_main}/{filename_input}")

# Set the border width and color
border_width = 4
border_color = blueprint["base_stroke_color"]

# Add the border to the image
image_with_border = ImageOps.expand(image, border=border_width, fill=border_color)

# Save the image with the border
image_with_border.save(f"{directory_main}/{filename_input}")

return 1


42 changes: 24 additions & 18 deletions portfoliofy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from datetime import datetime
import requests
from local_settings import user_input, system_input
from helpers import get_screenshot
from helpers import get_screenshot, get_screenshot_full
from output_browser import process_request_browser
from output_main import process_request_main
from output_mobiles import process_request_mobiles
from output_full import process_request_full


def main():
Expand All @@ -20,6 +21,7 @@ def main():
output_main = user_input.get("output_main")
output_browser = user_input.get("output_browser")
output_mobiles = user_input.get("output_mobiles")
output_full = user_input.get("output_full")

status_code = get_url(remote_url)

Expand Down Expand Up @@ -49,62 +51,66 @@ def main():
laptop = system_input.get("laptop")
tablet = system_input.get("tablet")
smartphone = system_input.get("smartphone")
full = system_input.get("full")

print(get_screenshot(remote_url, wait, directory_screenshots, desktop))
print(get_screenshot(remote_url, wait, directory_screenshots, laptop))
print(get_screenshot(remote_url, wait, directory_screenshots, tablet))
print(get_screenshot(remote_url, wait, directory_screenshots, smartphone))
get_screenshot(remote_url, wait, directory_screenshots, desktop)
get_screenshot(remote_url, wait, directory_screenshots, laptop)
get_screenshot(remote_url, wait, directory_screenshots, tablet)
get_screenshot(remote_url, wait, directory_screenshots, smartphone)
get_screenshot_full(remote_url, wait, directory_screenshots, full)

# ################################################## #
# 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 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 Request - OUPUT_MOBILES
# ################################################## #
if output_mobiles["request"] == True:

result = process_request_mobiles(
output_mobiles, system_input, directory_main, directory_screenshots)
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_FULL
# ################################################## #
if output_full["request"] == True:
result = process_request_full(output_full, full, directory_main, directory_screenshots)

if result == 1:
print("OUTPUT_FULL request processed.")

else:
print("OUTPUT_FULL not requested.")

# ################################################## #
# Process Request - OUPUT_SCREENSHOTS
# ################################################## #
if screenshots == False:

shutil.rmtree(directory_screenshots)
print("Screenshots directory deleted.")

Expand Down

0 comments on commit 4e2d03f

Please sign in to comment.